astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

そうだScalaでAsta4dを使おう

こんにちは、yanagitaです。

いつもPlay関連の話をしていますが、今回はAsta4dのscala対応についてお話します。
すでに本ブログでもasta4dの関する話はでていますが、元々Java向けのライブラリとなっているためScalaで使用とすると Scalaの良さ活かせないところや仕様上使えないメソッドなんかがあったりします。
そのあたりを対応したAPIと回避策を紹介します。

過去のAsta4dに関する記事はコチラ

事前準備

Scala向けのAPIの利用するにはasta4d-scalaライブラリを追加する必要があります。
以下、maven向け

<dependency>
    <groupId>com.astamuse</groupId>
    <artifactId>asta4d-scala</artifactId>
    <version>0.6</version>
</dependency>

以下、sbt向け

libraryDependencies += "com.astamuse" % "asta4d-scala" % "0.6"

Renderer定義のScala対応

シンプル定義

asta4d-scalaライブラリを読み込むことでRendererの定義にArrowAssocが使用できるようになります。

以下、コーディングの比較
Java表記

public Renderer render() {
  Renderer render = Renderer.create();
  render.add("#someIdForInt", 12345);  
  render.add("#someIdForLong", 12345L);  
  render.add("#someIdForBool", true);  
  render.add("#someIdForStr", "a str");  
  render.add("#someIdForNull", (Object) null);  
  render.add("#someIdForClear", Clear);
  Element newChild = ElementUtil.parseAsSingle("<div></div>");  
  render.add("#someIdForElementSetter", new ChildReplacer(newChild));  
  render.add("#someIdForElement", ElementUtil.parseAsSingle("<div>eee</div>"));  
  render.add("#someIdForRenderer", Renderer.create("#value", "value"));  
  return renderer;
}

Scala表記

import com.astamuse.asta4d.scala.R._
def render(): Renderer = {
  "#someIdForInt" -> 12345 &
  "#someIdForLong" -> 12345L &
  "#someIdForBool" -> true &
  "#someIdForStr" -> "a str" &
  "#someIdForNull" -> (null.asInstanceOf[Object]) &
  "#someIdForClear"-> Clear &
  "#someIdForElementSetter" -> new ChildReplacer("<div></div>".parseAsSingle()) & 
  "#someIdForElement" -> "<div>eee</div>".parseAsSingle() &
  "#someIdForRenderer" -> ("#value" -> "value") &
  "#someIdForRenderable" -> (()=>("#id" -> "xx").asRenderer())
}

ArrowAssoc定義のお陰でシンプルで読みやすくなり、scalaで書く方にとっては単純にコーディングできるようになったかと思います。
少し解説します。
scala側でArrowAssocを使ったコーディングを行うために「com.astamuse.asta4d.scala.R._」をインポートします。
続けて、定義はTuple2の第一引数にセレクタ、第二引数に挿入する値を設定します。これが1つのRenderer定義になります。

// 結果は一緒
render.add(セレクタ, 挿入する値); // Java
セレクタ -> 挿入する値 // Scala

複数Rendererを定義する場合は「&」でTuple2を繋いでいきます。
これはインポートしたR配下のメソッドがArrowAssocで定義されたTuple2を暗黙的にRendererオブジェクトに変換し、「&」でRenderer#addメソッドに変換する仕組みとなっています。
暗黙部分を取り除くと下のイメージとなります。

Scala表記

  "#someIdForInt" -> 12345 &
  "#someIdForLong" -> 12345L &
  "#someIdForBool" -> true &

Java表記

  Renderer.create("#someIdForInt", 12345)
    .add(Renderer.create("#someIdForLong", 12345L))
      .add(Renderer.create("#someIdForBool", true))

では、次は上記以外のRenderer定義について紹介します。

配列定義

Java表記

public Renderer render() {
  return Renderer.create("#someIdForRenderer", Arrays.asList(123, 456, 789), new RowRenderer<Integer>() {  
    @Override  
    public Renderer convert(int rowIndex, Integer obj) {  
        return Renderer.create("#id", "id-" + obj).add("#otherId", "otherId-" + obj);  
    } 
  });
}

Scala表記

import com.astamuse.asta4d.scala.R._
def render() = {
  "#someIdForRenderer" -> List(123, 456, 789).map { i => {
    "#id"-> ("id-" + i) & "#otherId"-> ("otherId-" + i)
  }}
}

配列を使用した場合はJava側で定義していたRowRendererが不要となり、mapメソッドのみで記述できるようになります。

属性定義

Java表記

public Renderer render() {
  Renderer render = Renderer.create();
  render.add("#id", "+class", "yyy");
  render.add(("#id", "-class") -> "zzz");
  render.add("#id", "+class", "xxx");
  render.add("#id", "value", new Date(123456L));
  render.add("#id", "href", null);
  render.add("#idstr", "value", "hg");
  render.add("#idint", "value", 3);
  render.add("#idlong", "value", 3L);
  render.add("#idbool", "value", true); 
  return render
}

Scala表記

import com.astamuse.asta4d.scala.R._
def render() = { 
  ("#id", "+class") -> "yyy" &
  ("#id", "-class") -> "zzz" &
  "#id" -> "+class" -> "xxx" &
  "#id" -> "value" -> new Date(123456L) &
  "#id" -> "href" -> null & 
  "#idstr" -> "value" -> "hg" &
  "#idint" -> "value" -> 3 &
  "#idlong" -> "value" -> 3L &
  "#idbool" -> "value" -> true 
}

ArrowAssoc定義で属性を指定する場合は、セレクタ、属性指定、挿入する値を一括りで定義します。

  (セレクタ -> 属性指定) -> 挿入する値
  or
  セレクタ -> 属性指定 -> 挿入する値

いかがだったでしょうか?
asta4d-scalaでscalaライクなコーディングができるようになったと思います。

メソッド名と予約語のバッティング対応

URLルールの定義でパラメータを設定する役割としてvarメソッドが存在しますが、 この「var」scalaでは予約語となっておりメソッド名や変数名に使用することができません。 回避方法としては2つ、
 1つ目がメソッド名をアクサングラーブでかこ囲って使用する。
 2つ目がvarメソッドと同じ処理を持つpathVarメソッドを使用する。
これでメソッド名のバッティングを回避できます。

// ↓ コンパイルエラー varが予約後
rules.add("/app/{name}/{age}", "/templates/variableinjection.html")  
     .var("extraVar", 1234);
// ↓ アクサン グラーブで囲ってコンパイルエラーを回避
rules.add("/app/{name}/{age}", "/templates/variableinjection.html")  
    .`var`("extraVar", 1234); 
// ↓ pathVarメソッドでコンパイルエラーを回避
rules.add("/app/{name}/{age}", "/templates/variableinjection.html")  
     .pathVar("extraVar", 1234);

個人的には後者を使って頂くのが違和感がない実装になるかと思います。

以上、JavaライブラリAsta4dをscalaで使用するための紹介でした。
今後Scala対応が進んでいく中で興味を持って頂ける方が少しでも増えることを願っています。
更新があればまたこちらでご紹介します。

■ asta4d-scala github.com

弊社まだまだエンジニア&デザイナーを絶賛募集中です。

Webデザイナー
Webアプリケーションエンジニア(Java)
Webアプリケーションエンジニア(Scala)
データ開発エンジニア

採用に関するQAコチラ lab.astamuse.co.jp

Copyright © astamuse company, ltd. all rights reserved.