Scala IDEを入れるとeclipseの標準出力が切り替わる件について

ある時からプラグインの開発時に別プロセスでeclipseを起動してもスタックトレースやらSystem.out.printlnを始め標準出力が一切出なくなった。これが出ないとマジで仕事にならないのでとりあえず調査した。
eclipse->Preferencesで開いたダイアログの、Scala>Logging設定に"Redirect standard out/err to log file."というチェックボックスを発見した。これにチェックが入っていると標準出力をログファイルに切り替えるようだ。ちなみにデフォルトでチェックが入っている。


f:id:mi_kami:20130626232208p:plain


Scala IDEのチケットに挙げてる人もいた。
Eager redirect of other plugins output


うーん、こういう勝手に設定変えるのはどうかと思うのだが...。

Play frameworkをherokuで動かすための最速手順

Instant Play Framework Starterを少しづつ読み進めてるが、先にherokuに上げる方法を調べておきたくなった。公開できるとやる気出るし。基本的には公式チュートリアルで言われるがままにやっていれば動く。

環境構築(Heroku toolbelt)

heroku関連のコマンドを利用する為に必要。以前インストールしてそのまま使っているので覚えていないが、ここからダウンロードして説明読めば何とかなると思う(適当)。

herokuにログイン

mikami-no-MacBook-Air:play-starter-scala mkouhei0910$ heroku login
Enter your Heroku credentials.
Email: hogehoge@fugafuga
Password (typing will be hidden): ...

Authentication successful.

各種ファイルの作成

conf/dependencies.yml

使っているPlayのバージョンに合わせて記述する。

# Application dependencies
require:
	- play 2.1.1

Procfile

公式のチュートリアルの通りにやっても動作しない(参考)。以下のように記述する。

web:    target/start -Dhttp.port=$PORT $PLAY_OPTS

公開

gitに登録

 $ git init
 $ git add .
 $ git commit -m "init"

デプロイ

 $ heroku create
 ...
 $ git push heroku master
 ...
 $ heroku ps:scale web=1

確認

あとは実際にアクセスして確認する。以下のコマンドでブラウザから開く事ができる。

 $ heroku open

f:id:mi_kami:20130625233648p:plain
http://mighty-hollows-9694.herokuapp.com/entries

gradleでeclipseプラグインプロジェクトのビルドを実行する

当初の目的だったeclipseプラグインのビルドを実行が出来たので書いておく。ただし、とりあえず出来るレベルなのであまり参考にならないかもしれない。

サンプル用のeclipse pluginプロジェクトの作成

  1. Package Explorerを右クリックして、New->Others...でnewウィザードを開く
  2. Plug-in Projectを選択
  3. ウィザードの最後にテンプレートを選択するページがあるので、ここで"Hello, World"を指定する

このプラグインはメニューバーにSample Menuを表示するだけの単純なプラグインだ。これをgradleでビルドする。

フィーチャーの追加とbuild.gradleの作成

  1. まずはgradleのプロジェクトに変換する。Project Explorerで右クリックしてConfigure->Convert to Gradle Projectをクリック
  2. build.gradleファイルをプロジェクト直下に作成する
  3. build.gradleをエディタで開き、javaeclipseのプラグインをapplyする。

build.gradle

apply plugin: 'java'
apply plugin: 'eclipse'

依存関係の解決

まずは依存しているjarをdependenciesに追加する。eclipseプラグイン開発をする場合、MANIFEST.MFに書かれているRequired Plug-inがそれに相当する。とりあえずorg.eclipse.ui等の必須プラグインはeclipse本体と同じ階層にあるpluginsフォルダに格納されているので、それを探しに行くように設定する。

f:id:mi_kami:20130625014844p:plain

build.gradle

dependencies {
	compile fileTree(dir: '/Users/mikamikuh/project/Scala/eclipse_scala_ide_dev/plugins/', include: '*.jar')
}

リソースの追加

これでビルドは出来るが、これだけだとjarにplugin.xmlやMANIFEST.MF等の必要なが含まれない。gradleではsrc/main/resourcesの配下に置いたファイルはすべてjarに追加されるが、これらのファイルを移動すると後々面倒なので追加するリソースを指定する。

build.gradle

sourceSets {
	main {
		java { srcDirs 'src' }
		resources {
			include "META-INF/*", "plugin.xml"
		}
	}
}

ビルドの実行

 $ gradle -q assemble
[sts] -----------------------------------------------------
[sts] Starting Gradle build for the following tasks: 
[sts]      :assemble
[sts] -----------------------------------------------------
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE

BUILD SUCCESSFUL

Total time: 4.805 secs
[sts] -----------------------------------------------------
[sts] Build finished succesfully!
[sts] Time taken: 0 min, 4 sec
[sts] -----------------------------------------------------

課題

以下の書き方が知りたい...。

  • 依存関係をMANIFEST.MFから自動で取得する
  • build.propertiesからjarに含む/含まないリソースを取得

eclipseでgradleを使うための環境構築

Yokohama.groovy #16に参加してきた。元々Groovyに興味はなかったが、Mavenやantに代わるgradleというビルドツールに興味があって、そのビルドスクリプトがGroovyで書けるのだ。
最終的には仕事で作っているeclipseプラグインプロジェクトをgradleでビルドしたいので、eclipse上でgradleを使ってビルドする環境を作った。その環境構築&操作方法をメモしておく。

gradleとは

f:id:mi_kami:20130623233715g:plain
gradleはビルドの為のツールで、従来のantやMavenと同じような物だ。antやMavenはすべてXMLでビルドスクリプトを記述していたのに対して、gradleはGroovyでビルド手順を記述する。ant、Maven、gradleのそれぞれ違いはおおまかに以下のような感じらしい。

  • antは何でも書けるが、とにかく書くのが大変(XML...)
  • Mavenは特定の範囲内であれば簡単に書けるが、そこを外れるとスクリプトを書くのが大変
  • gradleは何でも書けるし簡単に書ける(らしい)

まだ詳細に比較はしてないのでもう少しgradleを理解できたら比較記事を書く。

環境構築

gradle本体のインストール

Mac OS Xでgradleをインストールする場合、Homebrewを利用するのが一番早い。

$ brew install gradle
...
$ gradle -v

------------------------------------------------------------
Gradle 1.6
------------------------------------------------------------

Gradle build time: Tuesday, May 7, 2013 9:12:14 AM UTC
Groovy: 1.8.6
Ant: Apache Ant(TM) version 1.8.4 compiled on May 22 2012
Ivy: 2.2.0
JVM: 1.6.0_41 (Apple Inc. 20.14-b01-445)
OS: Mac OS X 10.8.2 x86_64

gradleプラグインのインストール

次にgradleをeclipseのUI上から実行する為の環境を整える。

  1. eclipseを起動して、Help->Install New Softwareを開く
  2. InstallウィザードでAddボタンをクリックし、http://dist.springsource.com/release/TOOLS/gradleをUpdateSiteとして登録する
  3. Extentions / Gradle IntegrationからGradle IDEにチェックを入れる
  4. Nextボタンを押し、ウィザードを進めてFInishボタンをクリック

f:id:mi_kami:20130623163849p:plain

Groovy IDEのインストール

ビルドスクリプトを編集する為にGroovyのIDEをインストールする。
gradleのプラグインのインストールと同じ手順で、ここから自分のeclipseのバージョンに合わせたUpdateSiteのURLを探して登録する。

gradleプロジェクトを作る

新規作成する場合

  1. ProjectExplorerを右クリックして、New->Others...を選択
  2. gradleプロジェクトを選び、Nextボタンをクリック
  3. プロジェクト名と、テンプレートを選択してFinishボタンをクリック

f:id:mi_kami:20130623235611p:plain

既存プロジェクトをgradleプロジェクトにする場合

  1. gradleプロジェクトにするプロジェクトを右クリックして、Configure->Convert to Gradle Projectを選択する

f:id:mi_kami:20130623234258p:plain

これでeclipseのプロジェクト自体はgradleプロジェクトになり、ネーチャーと必要な依存関係が追加される。追加で以下の作業が必要になる。

  • build.gradleのファイルの作成
  • ソースコードとテストコードのフォルダの切り直し(ビルドスクリプト内でこれらのパスを変更できる?)

gradleのビルドを実行する

  1. Window->Show ViewからGradle Tasksを選択して、Gradleのビューを表示させる。
  2. プルダウンメニューからビルドしたいプロジェクトを選択する
  3. 実行可能なタスクの一覧から実行したいタスクをダブルクリックするとそれが実行される
  4. build.gradleに書いたタスクを更新したら右上に表示されているRefreshボタンを押す事で反映される

f:id:mi_kami:20130624000449p:plain

終わりに

gradleのユーザーガイド(日本語訳)が非常に充実していて良かった。gradleを始めるときはこれを見れば大丈夫そう。なお、環境は作ったが暫くは挙動を理解する為にコマンドライン上で操作する予定。

『レガシーコード改善ガイド』の勉強会に参加しました

『レガシーコード改善ガイド』討論・品評会 #1 #lckaizenに参加してきました。最近はゲーム関連の勉強会に参加することが多かったので、こういう真面目な勉強会は久しぶりです。参加者のレベルが高くて恐れ入りました。

Togetterで本日の内容についてはまとめられるはずですが、いくつかのトピックについて考えたことを軽くまとめておきます。あまり議論に入っていけなかったので。

使い捨ての作業について

使い捨ての応急処置敵な作業をする必要があることはしばしばあると思います。バグを見つけたページに対して一時的に別のページを表示しておくとか、プレゼンでデモする為に一時的に動かしたいとか。そのときに、使い捨てになるようなコードを書いても良いのか?テストを書くか?という話。
同じような作業を2回以上する必要があるなら、正しく設計してレガシーなコードにならないようにしたほうがいいということでした。

モッキスト

何でもかんでもモックオブジェクトで試験する人は"モッキスト"と呼ばれているらしいです(JUnit実践入門を参考)。
僕自身は最初にテストの書き方を教わったとき、モックを使った書き方を教えてもらってそれで納得していたので、ずっとこの方法で書いていましたが...。
「モックを作るコスト」「更新するコスト」の2つを考えて、どちらを選択するか、および両方を採用するかを決める必要があります。

僕が基本的にJavaで試験を書く時は、"試験をする為に"(モックを使いやすくする為に)インターフェースを切る事が多かったので、それは本当の意味でインターフェースなのかを再考する必要がありそうです。

レガシーコードは成果物

印象に残った言葉。

レガシーなのは人であり、レガシーコードは成果物なのだ


後で思い出したらもう少し足します...。

Scalaにおけるシングルトンオブジェクトとは

Playの本を読んでいたらシングルトンオブジェクトを利用するコードをよく目にしたのでメモ。

シングルトンオブジェクト

Scala特有の機能がシングルトンオブジェクトの定義だ。ScalaJavaとは違って静的なメンバを持つ事ができないが、シングルトンオブジェクトを作る事でJavaの静的な関数のように扱う事ができる。

object ChecksumAccumulator {
    private val cache = Map[String, Int]()
    def calculate(s: String): Int =
    ....
}

コンパニオンクラス

シングルトンオブジェクトが同名のクラスを持つとき、それをコンパニオンオブジェクトと呼ぶ。クラスとコンパニオンオブジェクトは同じソースファイルで定義しなければならないが、それらは互いの非公開メンバーにアクセスできるという特徴を持つ。

class Rocket {
  import Rocket.fuel
  private def canGoHomeAgain = fuel > 20
}

object Rocket {
  private def fuel = 10
  def chooseStrategy(rocket: Rocket) : String = {
    if (rocket.canGoHomeAgain)
      goHome()
    else
      pickAStar()
  }
  
  def goHome() : String = { "goHome" }
  def pickAStar() : String = { "pickAStar" }
}

利用例

これは以下のように呼び出せる。

$ var rocket = new Rocket
$ Rocket.chooseStrategy(rocket)
> goHome

rocketクラスを作成し、コンパニオンオブジェクトのchooseStrategy関数をrocketを引数にして呼び出す。すると、privateで宣言されているRocketクラスのcanGoHomeAgain関数を呼び出せる。

Scalaのインポートについてメモ

Instant Play Framework Starterを読み進めているが、Scalaを書いた事が無いので調べながら読み進めている。とりあえず、コップ本を読みながらパッケージのインポート周りを整理したのでメモしておく。

基本的なインポート文

クラスやオブジェクトを直接インポートするsingle type(単一型)と、パッケージ配下の全てのメンバをインポートするon demand(オンデマンド型)の2種類が存在する。on demandはJavaの*を使ってアクセスするのと等価。

// Fruitオブジェクトへのインポート(single type)
import bobsdelights.Fruit

// bobdelightsパッケージ下のすべてのメンバへアクセスする為のインポート(on demand)
import bobdelights._

任意の場所でインポート

Javaではソースの冒頭だけでなく、任意の場所でインポートできる。以下のように関数の内部でインポートを記述しても文法的には間違っていない。

def showFruit(fruit: Fruit) {
    import fruit._
    println(name + "s are " + color)
}

それだけでなく、Fruitオブジェクトを直接参照できるようになる。printlnで使用されているnameとcolorはFruitに定義されているメンバだ。

インポートセレクタ

インポートセレクターという機能を使うと特定のメンバーだけをインポートすることが出来る。特定のメンバだけ名前を変えたり、隠したりできる。これらは名前が重複する場合に重宝する。

// FuitsオブジェクトからApple, Orangeだけをインポートする
import Fruits.{Apple, Orange}

// FruitsオブジェクトのAppleを、McIntoshという名前でインポートする
import Fruits.{Apple => McIntosh, Orange}

// すべてのメンバをインポート(Fruits._と等価)
import Fruits.{_}

// Fruitsのメンバをインポートし、AppleをMcIntoshという名前でインポートする
import Fruits.{Apple => McIntosh, _}

// Pear以外のメンバをインポートする
import Fruits.{Pear => _, _}

暗黙のインポート

Scalaで何もインポートしなくても、以下のパッケージは暗黙のうちにインポートされる。

import java.lang._
import scala._
import Predef._

なので、scala.ListはListと書くことができる。java.langとscalaの両方のパッケージにStringBuilderが定義されているが、scalaのインポートがjava.langのインポートを隠す為、StringBuilderという単純名で参照されるクラスはscala.StringBuilderとなる。