Skip to content

Scala や Play! framework で DI

Scala や Play! framework で DI published on Scala や Play! framework で DI へのコメントはまだありません

自分用メモ

 

PHPからGoogle Spreadsheets APIを使う

PHPからGoogle Spreadsheets APIを使う published on PHPからGoogle Spreadsheets APIを使う へのコメントはまだありません

同じことやるの2度目なのに、すっかり忘れてしまっていたので、3度めに備えてメモ。

やりたいこと

(MySQLに入っている)あるデータを、Google Spreadsheets APIを使ってスプレッドシートに書き込む。

使うもの

以下のライブラリを使う。

Continue reading PHPからGoogle Spreadsheets APIを使う

elastic4s でエラー処理

elastic4s でエラー処理 published on elastic4s でエラー処理 へのコメントはまだありません

Scala から Elasticsearch を操作するクライアントライブラリ

Elasticsearch のサイトには、以下の4つが紹介されている

更新具合その他を考えて、elastic4sを使うことにした。

Elastic4s の使い方 → RTFM

基本的な使い方は以下を参照。

エラー処理

ドキュメントだと、エラーが起きた時にどう処理をすれば良いかが書いていない。

例えば、documentを追加するコードは

esClient.execute {
   index into s"index1/type1" fields ("field1" -> "val")
}

みたいに書くけど、エラーが起きたらどうするんだろうと思った。

上の式のシグニチャーをみると Future[IndexResponse] らしい。IndexResponse は Elasticsearch の API で提供されている。ドキュメントはこの辺

ドキュメントに追加できなかった場合は、isCreated メソッドが false を返す。それ以外に、サーバー側でエラーが起きたりとかした場合には例外が投げられる。

ということで、例えば以下のように処理できる。

import com.sksamuel.elastic4s.ElasticDsl._
import org.elasticsearch.action.index.IndexResponse
import org.elasticsearch.transport.RemoteTransportException

val f: Future[Boolean] = esClient.execute {
   index into s"index1/type1" fields ("field1" -> "val")
} map (_.isCreated) recover {
  case e: RemoteTransportException =>
    Logger.error(e.getMessage)
    false
}

この辺はニーズに応じて好きなようにすれば良いかなと。

その他

コードをみたけど、結構ちゃんと書かれていた(と個人的には思った)。

まとめ?

Elasticsearch 便利。elastic4s も便利。

Cordova 3.6 + Geolocation plugin in iOS 8

Cordova 3.6 + Geolocation plugin in iOS 8 published on Cordova 3.6 + Geolocation plugin in iOS 8 へのコメントはまだありません

Cordova + Geolocation Plugin で iOSアプリを作ってる

Cordova で iOS アプリを初めて作ってる。JavaScript は比較的得意なので、HTML + JS で簡単にアプリが作れて便利。

スマホアプリの場合、位置情報機能を使ったものが多くて、その場合には Cordova の Geolocation plugin というものが使えるんだけど、2点ほどつっかえたところがあったのでメモ。

環境

  • Apache Cordova 3.6.3
  • Geolocation plugin 0.3.11
  • (多分あまり関係ないけど)Xcode 6.1.1

対象プラットフォームは、今の所 iOS のみ。

インストールとか

通常通り plugin をインストールすればいいので、省略。

使ってみたら、エラーが2つほど

1. plist に何か必要らしいが・・・

一つ目のエラーは、以下の様なログ。

[Warning] No NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key is
 defined in the Info.plist file.

ググってみると、SOにこんなのが。 Info.plist に記述を追加する必要があるらしい?

でも、この辺や、オフィシャルの情報(これこれ)見るとpluginがiOSに対応したって書いてあって、ドキュメントにも特にplistを直接いじるような事も書いてない。

結論から言うと、最新のプラグインを使っていれば問題ない。

自分の場合は、plist を手動でゴニョゴニョ修正するhookを使っていたので、それが原因だった。

2. getCurrentPosition が失敗

ようやくプラグインが動作したと思ったら、以下の様なエラーが。

1行目はプラグインが直接コンソールに出力した(?)ログで、2行目と3行目は、navigator.geolocation.getCurrentPosition の第2引数のコールバック(エラー時に呼ばれる)関数の中で、受け取ったエラーコードとエラーメッセージを表示させたもの。

locationManager::didFailWithError (null)
code: 2
message: The operation couldn<E2><80><99>t be completed. (kCLErrorDomain error 0.)

これは、どうやらiPhone Simulator のみで起こる問題っぽい。SOのこれを見て、ダメ元でDebug -> Location で “Custom Location” 以外を選択したら問題が解消した。その後、再度 Custom Location を選択しても問題なし。

まとめ

Cordova + Geolocation plugin は便利だけど、エラーが起きた時の情報がちょっと少なくて、予想外に時間がかかってしまうことがあるなぁと。

Scalaの型引数とかサブ型とか

Scalaの型引数とかサブ型とか published on Scalaの型引数とかサブ型とか へのコメントはまだありません

コンパイルが通らない

以下のコードのコンパイルが通らないので、どうしたものかと質問した。

abstract class C
case class C1() extends C
case class C2() extends C

trait Service[T <: C] {
  def getFoo(): Option[T]
}

object Service {
  // found   : List[Option[Any]]
  // required: List[Option[T]]
  def getAllFoos(services: List[Service[_]]): List[Option[C]] = {
    services.map(_.getFoo())
  }
}

(答えだけ知りたい場合は、@gakuzzzz さんのコメントが簡潔かつ完全な内容なのでそちらを参照。)

エラーの原因

さて、エラーの原因は @gakuzzzz さんの解説にある通り。

ポイントは trait Service[T <: C] にした場合、 Service[C] と Service[C1] と Service[C2] が全然関係ない型になってしまうので、統一的に扱えないって所ですね。

(なぜ全然関係ない型になってしまうのだろう。調べないと。)

試行錯誤

@xuwei-k さんに教えてもらった方法

@xuwei-k さんに教えてもらった方法だとコンパイルは通った。

object Service {
  def getAllFoos[A <: C](services: List[Service[A]]): List[Option[C]] = {
    services.map(_.getFoo())
  }
}

ただ、元のgistで端折ってしまったんだけど、@gakuzzzz さんが書いたように、実際にはServiceは以下のように継承して使うことを前提としてる。

object C1Service extends Service[C1] { def getFoo(): Option[C1] = None }
object C2Service extends Service[C2] { def getFoo(): Option[C2] = None }

servicesにC1ServiceとC2Serviceが混ざったものを渡すとエラーになった。

scala> Service.getAllFoos(List(C1Service))
res4: List[Option[C]] = List(None)

scala> Service.getAllFoos(List(C2Service))
res5: List[Option[C]] = List(None)

scala> Service.getAllFoos(List(C1Service, C2Service))
<console>:17: error: no type parameters for method getAllFoos: (services: List[Service[A]])List[Option[C]] exist so that it can be applied to arguments (List[Service[_ >: C2 with C1 <: Product with Serializable with C]])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : List[Service[_ >: C2 with C1 <: Product with Serializable with C]]
 required: List[Service[?A]]
              Service.getAllFoos(List(C1Service, C2Service))
                      ^
<console>:17: error: type mismatch;
 found   : List[Service[_ >: C2 with C1 <: Product with Serializable with C]]
 required: List[Service[A]]
              Service.getAllFoos(List(C1Service, C2Service))

エラーの意味がよく分からないが、「Service[C] と Service[C1] と Service[C2] が全然関係ない型になってしま」ってるという事なのかな。

@gakuzzzzさんに書いてもらった方法1

こちら

abstract class C
case class C1() extends C
case class C2() extends C

trait Service[+T <: C] { // ここがポイント
  def getFoo(): Option[T]
}

object Service {
  def getAllFoos(services: List[Service[C]]): List[Option[C]] = {
    services.map(_.getFoo())
  }
}

object C1Service extends Service[C1] { def getFoo(): Option[C1] = None }
object C2Service extends Service[C2] { def getFoo(): Option[C2] = None }

Service.getAllFoos(List(C1Service, C2Service))

うまく行った。

これを trait Service[+T <: C] とすれば、Service[C1]Service[C2]Service[C] のサブ型と見做せるようになるので Service[C] として統一的に扱えるようになります。

とのこと。

@gakuzzzzさんに書いてもらった方法2

gistはこちら

abstract class C
case class C1() extends C
case class C2() extends C

trait Service {
  type T <: C
  def getFoo(): Option[T]
}

object Service {
  def getAllFoos(services: List[Service]): List[Option[C]] = {
    services.map(_.getFoo())
  }
}

object C1Service extends Service { type T = C1; def getFoo(): Option[C1] = None }
object C2Service extends Service { type T = C2; def getFoo(): Option[C2] = None }

Service.getAllFoos(List(C1Service, C2Service))

こちらに関しても先生のコメント。

型引数を止めて、抽象メンバ型でやれば、Service という型は一つになるので、こちらも Service で統一的に扱えるようになります。 type T = C1 が必要なのはこの場合ですね。

使い分け

これも先生のコメントそのまま書いとく。

共変を使うか、抽象メンバ型を使うか、の判断基準としては、「C1に特化したServiceの型を扱いたいかどうか」になるかと思います。

なるほど。

考えたこと

これだけだと、@xuwei-k さんと @gakuzzzz さんのコメントを切り貼りしただけなので、もう少し書いておく。

そもそもの動機

実際のコードだと、C1とかC2はユーザーの外部アカウントとの連携情報で、例えば以下の様なもの(簡略化してるけど)。どれとも連携していない人もいれば、全てと連携している人もいる。

  • Facebook連携の情報: UserFacebookInfo
  • Twitter連携の情報: UserTwitterInfo
  • GitHub連携の情報: UserGitHubInfo

それぞれが抽象クラスUserExternalAccountInfoを継承している。

で、Serviceに当たるのはいくつかあるけど、例えばDAOで、それぞれ違うテーブルにデータが入っているので(それぞれ user_facebook_info, user_twitter_info, user_github_info テーブル)、別々のDAOを用意した。以下の感じ。

trait ExternalAccountInfoDao[T <: UserExternalAccountInfo] {
  def getInfo(userId: Int): Option[T]
}

object ExternalAccountInfoDao {
  def getAllAccounts(userId: Int): List[Option[UserExternalAccountInfo]] = {
    val daos = List(UserFacebookInfoDao, UserTwitterInfoDao, UserGithubInfoDao)
    daos.map(_.getInfo(userId))
  }
}

object UserFacebookInfoDao
 extends ExternalAccountInfoDao[UserFacebookInfo] {
  def getInfo(userId: Int): Option[UserFacebookInfo] = { /* code */ }
}
// UserTwitterInfoDao, UserGithubInfoDao も同様

(多分もっと良い設計がありそうなので、コメント大歓迎です。)

その他

コメントで書いてもらったコードを見れば内容は分かるんだけど、自分であういうコードがパッと出てこないところが実力不足だと思った。

人のコードを沢山読んだり、定石(いわゆるデザインパターン)をもっと勉強しないといけないなと思った。

sbtでstacktraceを全部表示させる

sbtでstacktraceを全部表示させる published on sbtでstacktraceを全部表示させる への2件のコメント

自分用メモ。

Play! frameworkを使った開発で、エラー発生時にstacktraceが途中で途切れてしまう事がある、

ScalaTestの場合は、こちらにあるように以下のように指定する。

testOptions in Test += Tests.Argument("-oD")

sbt自身の話だが、デフォルトでは大抵のstack traceは隠されてしまう。

By default, sbt hides the stack trace of most exceptions thrown during execution. It prints a message that indicates how to display the exception. However, you may want to show more of stack traces by default.

表示するためには以下のようにする。詳しくはマニュアル参照。

> set every traceLevel := 0

最初からonにしててくれればいいのに。

追記:

xuwei_kさんからのコメントの通り、lastとやると、最後に実行したコマンドに関するログが出力される。マニュアルの一番上に書いてある。

When a command is run, more detailed logging output is sent to a file than to the screen (by default). This output can be recalled for the command just executed by running last.

Slick 2.0.xをPlay! framework2.2から使う

Slick 2.0.xをPlay! framework2.2から使う published on Slick 2.0.xをPlay! framework2.2から使う へのコメントはまだありません

はじめに

タイトルにPlayも含めてるけど、今回のエントリーは主にSlick 2.0.xの話。

そして、最初に一言言わせて欲しい。Slickのドキュメントは分かりにくい or 不十分。ただ、「お前が貢献しろよ」、という真っ当な指摘が来そうなので、これに関してはあまり深入りはしない。

まずは今回の目的を。

目的・ゴール

簡単に今回の目標を書いておく。

  • Play! framework 2.2.xで、Slickを使ってDBにアクセスする。
  • DBのスキーマからコードを自動生成する機能を使う。

後者に関してだけど、DBのテーブルは生のSQLを使うことが多いので、あると非常に便利。幸い、Slickにはコード自動生成の機能があるので、それを使う。

ScalaのDB library

本題に入る前に、今回のエントリーの背景を少し。

今実験的に動いているプロジェクトでは、前回のプロジェクトと同じくPlay! 2.2を使うことにした。慣れてるし。でも、せっかくだし何か新しいことも試さないと、ということで、DBライブラリーは今まで使ったこと無いSlickを使うことにした。

今まではSquerylScalikeJDBCを使った事があって、どちらにも大きな不満はそれほどなかった。実際、両方共いいライブラリだと思う。後から出てきたScalikeJDBCの方が設計は綺麗だと思うけど。

その他、Play!の場合Anormという選択肢もあるけど、知り合いの信頼の置ける開発者から「論外」みたいな話を聞いたことがあるし、ドキュメントを見る限り基本的というか低レベルなので、あまり開発効率向上にはつながらなさそう、ということで除外。

環境

さて、本エントリーの環境。

  • Play! framework 2.2.2
  • play-slick 0.6.0.1 (Play!でSlickを使うためのプラグイン)
  • Slick 2.0.0 (play-slickのバージョンによって使えるSlickのバージョンが異なる)

以下、本題。

Continue reading Slick 2.0.xをPlay! framework2.2から使う

PHPマニュアルの関数リファレンスを隅から隅までざっと読んでみた

PHPマニュアルの関数リファレンスを隅から隅までざっと読んでみた published on PHPマニュアルの関数リファレンスを隅から隅までざっと読んでみた へのコメントはまだありません

知らない関数や機能をなくしたい!

PHPの歴史って長くて、その間に付けたし付けたしでどんどん関数が増えていき、PECLモジュールもかなりの数になっている。

なので、普段PHPをよく使っている人でも、結構知らない関数や機能があったりする。かくいう自分もちょくちょく新しい関数を発見して、その都度「もっと早くに知っていれば」という悔しい思いをしていたんだけど、この度

PHPマニュアルの関数リファレンスを全部読んで、知らない関数や機能を発見しよう!

と思いついたので、実行してみた。

注意事項

以下、筆者が知らなかった、あるいは知っていたけど載せる価値がある、と思ったものを載せているので、読んでいる方にとって自明の事であったり、あるいはここに載っていないけど読んでいる方にとって知らないものとかがあるかもしれない。

と言う事で、善良なPHPerの皆さんは、各自でマニュアルを読み込む事をお勧めする。

Continue reading PHPマニュアルの関数リファレンスを隅から隅までざっと読んでみた

SquerylでPostgreSQLのgeometry関連関数を使う

SquerylでPostgreSQLのgeometry関連関数を使う published on SquerylでPostgreSQLのgeometry関連関数を使う への1件のコメント

以前別ブログで、Squerylで最初からは用意されていない集計関数(median)を実装する、というエントリを書いた。今回はそれと似た内容で、PostgreSQLの位置情報の関数をSquerylで使えるようにしてみる。

Squeryl 0.9.5-6

距離を調べるSQL

今回使いたいのは、2点間の距離を調べる <-> という関数。例えば、以下のクエリーのように、ある位置(36.726637,139.526557)から3000m以内にある点のうち、距離が近い順に30件取得したいとする。これをSquerylを使って実現したい。

SELECT p.*, (p.latlng <-> POINT(36.726637,139.526557)) * 111000 as l
FROM place p
WHERE (p.latlng <-> POINT(36.726637,139.526557)) < 3000.0 / 111000.0
ORDER BY p.latlng <-> POINT(36.726637,139.526557)
LIMIT 30

Continue reading SquerylでPostgreSQLのgeometry関連関数を使う

FabricでPlay! frameworkアプリのデプロイを自動化してみた

FabricでPlay! frameworkアプリのデプロイを自動化してみた published on FabricでPlay! frameworkアプリのデプロイを自動化してみた へのコメントはまだありません

随分前から、勉強がてら個人でちょこちょこwebサイト作ってる。デプロイはjarファイルのコピーだけとは言え、毎回手動でdeployとサービス再起動をするのはさすがに面倒になってきたので、デプロイを自動化するツールを導入する事にした。

環境等

  • Play! framework 2.2
  • web(app)、DB、バッチでサーバーが分かれている
  • デプロイ先はいずれもLinux
  • ローカル開発環境はOS X Mavericks (10.9)
  • Fabric 1.8.1を使用

Continue reading FabricでPlay! frameworkアプリのデプロイを自動化してみた