来世から頑張る!!

技術ブログを目指して

一般的なShellで空白を含むPathをループしたい願望

まず、Shellって何かがわからないところから入るわけだけど、 いや、自分が打っているのが所謂shなのかbashなのかzshなのかがわからないってことなんだけど、 まあ複数ファイルを順次処理したい時ってあるわけですね。

forを使ったループ

シンプルな例だと以下のように書くわけです。

  for f in path/to/target/*.txt
  do
    echo "file is: $f"
  done

このディレクトリーにa.txt, b.txt, c.txtがあれば、以下のように表示されるでしょう。

file is: path/to/target/a.txt
file is: path/to/target/b.txt
file is: path/to/target/c.txt

スペース(など)が含まれたパス

ところが、スペースが含まれているようなディレクトリー名だと、これがうまく動かないのです。

ディレクトリー名をpath/to target with space/だとしてみましょう。

ls "path/to target with space/"
a a.csv      b c d.csv

こんな場合ですね。

同じようなループを実行すると、当然うまく行きません。

for f in path/to target with space/*.csv
do
  echo "file is: $f"
done

結果はこんな感じになったりしてしまいます。

file is: path/to
file is: target
file is: with
file is: space/*.csv

解決方法1: IFS組み込み変数を使用

どうにかスペース入のパスをループできないのかなーと検索した結果見つけたのが、 組み込み変数IFSfindコマンドを組み合わせる方法です。

IFSを変更すると、shellが扱う区切り文字を変更できるとこのことです。

まずfindを実行すると、以下のような結果が取得できます。

> find "path/to target with space" -type f -name "*.csv"
path/to target with space/a a.csv
path/to target with space/b c d.csv

結果が改行されて出てくるので、IFSに改行記号\nを設定後ループするとうまくいくようです。
ただし、IFSを元に戻せるように、退避してから実行した方が良いようです。

IFS_BACK="$IFS"
IFS=$'\n'
for f in `find "path/to target with space" -type f -name "*.csv"`
do
  echo "file is: $f"
done
IFS="$IFS_BACK"
file is: path/to target with space/a a.csv
file is: path/to target with space/b c d.csv

解決方法2: ""でくくる

とりあえず上をコピペして使っていたのですが、 今日もっと簡単にできる方法を発見してしまったのでそちらに書き換えることにしました。

皆さんご存知のように、shellではダブルクォートに囲まれた部分は1つとみなしてくれるのです。
ただし、中にある*は展開してくれません。

まず、ダメな例。

for f in "path/to target with space/*.csv"
do
  echo "file is: $f"
done

これの結果は以下のようになります。

file is: path/to target with space/*.csv

*がそのままですね。

すごく単純すぎて気づかなかったのですが、 *をダブルクォートの外に出してあげれば展開されるんですよね、これ。

for f in "path/to target with space/"*".csv"
do
  echo "file is: $f"
done
file is: path/to target with space/a a.csv
file is: path/to target with space/b c d.csv

どこでダブルクォートを終わらせてもいいみたいなので、変数の部分だけくくるとかが現実的なのかなという感じです。

BASE_PATH="path/to target with space"
for f in "$BASE_PATH"/*.csv
do
  echo "file is: $f"
done

結論

shell難しい。

自分のshell力の低さを痛感させられた。

自分用メモ #scala

アレ用のアレ。

implicit def fs2effectTask: fs2.util.Effect[scalaz.concurrent.Task] = {
  import scalaz.concurrent.Task
  import fs2.util.Effect
  
  new Effect[Task] {
    def fail[A](err: Throwable) = Task.fail(err)
    def attempt[A](t: Task[A]) = t.attempt.map(_.toEither)
    def pure[A](a: A) = Task.now(a)
    def bind[A,B](a: Task[A])(f: A => Task[B]): Task[B] = a flatMap f
    override def delay[A](a: => A) = Task.delay(a)
    def suspend[A](fa: => Task[A]) = Task.suspend(fa)

    override def toString = "fs2.util.Effect[scalaz.concurrent.Task]"
  }
}

SQL99のWITH句について

MySQLしか触った事のない人にとっては全く知らない文法だというとこを最近知ったので。

WITH句とは

WITH句は、ネストされたテーブルに別名をつけて読みやすくするために使用する構文。

PostgreSQL, Oracle, MS SQL Serverなどで使用可能。 MySQLは(少なくとも少し前のバージョンでは)対応していない。

-- ネストされたテーブル
SELECT
    *
FROM
    (
        SELECT
            user_id,
            SUM(payment) AS total_payment
        FROM
            payments
        GROUP BY
            user_id
    ) a
WHERE
    a.total_payment > 3000

この例だとHAVINGすればいいとかはひとまず無視して、WITHを使うとこんな感じ。

WITH a AS (
    SELECT
        user_id,
        SUM(payment) AS total_payment
    FROM
        payments
    GROUP BY
        user_id
)

SELECT
    *
FROM
    a
WHERE
    a.total_payment > 3000

通常の言語の変数宣言と同じ!!便利!!! 変数のように、適切な名前をつけるべき。aとかbとかfとか。

複数の変数を使用する

WITH句で複数のテーブルを取得する場合、,で繋げる。

WITH a AS (SELECT ...),
b AS (SELECT ...),
c AS (SELECT ...)

SELECT * FROM c

自分より上で宣言された別名は利用可能!!

WITH a AS (
    SELECT
        user_id,
        MAX(log_date) AS log_date
    FROM
        some_log
    GROUP BY
        user_id
),
b AS (
    SELECT
        *
    FROM
        some_log s
    WHERE
        EXISTS(
            SELECT
                0
            FROM
                a
            WHERE
                a.user_id = s.user_id
                AND
                a.log_date = s.log_date
        )
),

...

再帰

一部条件を満たせば、自分自身の中でも再帰的に参照が可能。

WITH a AS (
    SELECT 0 AS index
    UNION
    SELECT index + 1 AS index FROM a WHERE index < 2
)
SELECT * FROM a
  • PostgreSQLではWITH RECURSIVE a ASとしないと不可。他のDBは知らない。
    つまり1番目の変数のみ再帰可能。

関数型の再帰と同様に、ループの終了条件書かないと無限ループして返ってこないので注意。

結果はこんな感じ。

index
=====
0
1
2
3

これを利用すれば「n月m日からo日までの毎日、0件なら0を取得する」なども簡単ですよね?

パフォーマンスについて

WITH句で別名をつけた場合、1つの名前につき最大1回しか読み込まれないことが保証される。 また、ほとんどのDBMSではSQLを最後まで読み込んだうえで最適化するので、インデックススキャンで済むものは一時テーブルを作成しない。 なのでネストした表現と最低限同等、読み込み回数によってはWITHの方が圧倒的に効率化が可能。

でも、最後に信じるべきはオプティマイザーですね。過信ダメ、ゼッタイ。

あ、MySQLではCREATE TEMPORARY TABLE 〜 SELECT 〜を使おう。
こっちは自分でインデックス貼れるのでもっと早いよ!!!

AnsibleでDockerとかしたいのにdocker-pyに苦しめられた話

はい。タイトル通りです。

ansibleとはpythonで動いてるけどpython書かなくてもいい不思議な何かという認識。

で、ansibleからdockerコンテナー立ち上げるときのレシピがこちら。

---
- name: Run CentOS container
  docker:
    image: "centos:centos6"
    name: sample001
    tty: yes
    net: host
    docker_api_version: 1.18

net=hostはネット設定はデフォルト不可だよというエラーメッセージ用、 docker_api_version=1.18は本番で動いてるdockerのバージョン違うよ用です。

なのですが、これを実行してもdocker-pyが見つからないよ系エラーが出るのです。

ということでローカルでpip install docker-pyしたりしてみたのですが、 これが一向に消えてなくならない。

virtualenvがダメなのかもとか悩んでいろいろググったり試したりした結果・・・

docker-pyは設定先の環境のデフォルトpythonに必要でした!!

はい。ローカルに入っていようが関係なかったのです。 よって、必要なのは設定先ホストでのpip install

これもansibleに書いてしまいます。

---
- name: Install docker-py
  become: yes
  become_method: sudo
  become_user: root
  pip:
    name: "docker-py"
    version: 1.7.1
    state: present

ansibleの恒等性とかを考えると、state=latestとどっちがいいのかわかりません。

sudoはたぶん必要。と信じている。

このためにはサーバーにもpipが入っていないといけないので、 それはサーバーのディストリビューションに合わせてって感じになるのかと。

私からは以上です。

GolangでShift_JIS(Windows31J)のファイルを読み込み

たどり着くまで時間がかかったのでメモ。

文字コードを意識しないファイルの読み込み

つまりはUTF-8のファイル。BOMはどうなんだろう?(試していない)

os.Openbufio.NewReaderで行ごとに読み込める。

注意点: 読み込み完了時はerrorio.EOFが入る。

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    path := "/path/to/your/file"
    fp, err := os.Open(path)
    if err != nil {
        panic(err)
    }
    defer fp.Close()

    reader := bufio.NewReader(decoder.Reader(fp))
    for {
        line, _, err := reader.ReadLine()
        if err == io.EOF {
            break
        } else if err != nil {
            panic(err)
        }
        fmt.Println(string(line))
    }
}

文字コードを考慮する。

とりあえずgolang decodeとかでググってみるとencodingパッケージが出てくる。

どうやらDecoder.ReaderでラップしたReaderが作れそう。

じゃあDecoderってどうやって作るの?と探したところ、japaneseパッケージShiftJISを発見。 こいつがencoding.Encoding型なので、NewDecoderメソッドを持っているらしい。

とりあえずjapaneseパッケージをゲット

go get golang.org/x/text/encoding/japanese

package main

import (
    "bufio"
    "fmt"
    "golang.org/x/text/encoding/japanese"
    "io"
    "os"
)

func main() {
    path := "/path/to/your/file"
    fp, err := os.Open(path)
    if err != nil {
        panic(err)
    }
    defer fp.Close()

    decoder := japanese.ShiftJIS.NewDecoder()
    reader := bufio.NewReader(decoder.Reader(fp))
    for {
        line, _, err := reader.ReadLine()
        if err == io.EOF {
            break
        } else if err != nil {
            panic(err)
        }
        fmt.Println(string(line))
    }
}

bufio.NewReaderに変換する前にデコードをはさめばOK
わかれば簡単。

ScalaでゆるふあにDB接続


この記事はScala Advent Calendar 2015 12日目です。

www.adventar.org

昨日は同じく私による今日から始めるScalaプログラミングでした。

前置き

私はアプリケーションにSQLを自分で書きたい派です。
参考: ScalaでSQLが書きたいんだ!!

なので積極的に自分で書けるライブラリーが好きです。

  1. DBに直接繋いで、取得結果や処理速度などを調整するクエリーを書く。
  2. 出来上がったクエリーを作成するためのScalaコードを書く。

こんな風に作業したいのです。

doobie or not DB

ということでdoobieです。

doobieによるシンプルなDBアクセスコードは以下のような感じです。

import doobie.imports._

case class User(id: String, password: String, email: Option[String])

object User {
  def byId(id: String): ConnectionIO[Option[User]] =
    sql"SELECT id, password, email FROM users WHERE id = ${id}".query[User].option
}

呼び出す側はこちら

import doobie.imports._
import scalaz.effect.IO

val xa = DriverManagerTransactor[IO](
  "com.mysql.jdbc.Driver", "jdbc:mysql://example.com:3306/example", "user", "password"
)
val a: ConnectionIO[Option[User]] = User.byId("kazzna")
val b: IO[Option[User]] = a.transact(xa)
val c: Option[User] = b.unsafePerformIO

これの素晴らしいところは、接続情報がxaにまとめられていて、それを明示的に渡すということですね。

ちなみにDriverManagerTransactorの型引数はscalaz.Catchableを要求してきたりするので、 IO以外ではscalaz.concurrent.Taskぐらいしか使える型を知りません。
(きっとガチ勢がコメントしてくれるはず・・・)

テストを書いてみる

最初に書いた通り、SQLが正しいことは確認してからScalaコードを書きたいので、 ユニットテストでDBになんて繋ぎたくないんですね。

ユニットテストで確認するのは「使用したいSQLが出力されているか」までで、 外部との接続はもうちょっと結合度の高いテストでやりたいわけです。

ですが世間一般のライブラリーはいつの間にかDB接続が暗黙的に渡されていたりして、 テストしようと思うと色々なテクニック(モックとか)を使わないと難しかったりします。

ところがこのdoobieはゆるふあ仕様で、それが簡単にできるのです!!!

val a = User.byId("kazzna") // ConnectionIO[Option[User]]
val b = a.transK[IO] // Kleisli[IO, java.sql.Connection, Option[User]]

Kleisli[M[_], A, B]とはゆるふあに言えばA => M[B]です。
なのでこの場合はb: java.sql.Connection => IO[Option[User]]ですね。

つまりjava.sql.Connectionを渡せばテストできるわけです。
このinterfaceを実装しましょう。

import java.sql._

import org.scalatest._

class QueryChecker(sql: String, params: Map[String, Any], result: ResultSet) extends Connection with Matches {
  override def prepareStatement(s: String): PreparedStatement = new PreparedStatement {
    s should ===(sql)
    override def setString(i: Int, s: String): Unit = {
      params(i) should ===(s)
    }
    override def executeQuery(): ResultSet = result
    // override def ... = ??? を必要なだけ書く
  }
  // override def ... = ??? を必要なだけ書く
}

class DummyResultSet(v: List[Map[Int, Any]]) extends ResultSet {
  var rowIndex = -1
  override def next(): Boolean = {
    rowIndex = rowIndex + 1
    rowIndex < v.length
  }
  override def getString(i: Int): String = v(rowIndex)(i).asInstanceOf[String]
  // override def ... = ??? を必要なだけ書く
}

気を付けるべきことは、import java.sql._java.sql.Arrayがimportされるため、 scala.Array[A]Arrayと書けないことです。
scala.Arrayと全部ちゃんと書く必要があります。もしくは別名import。

あと、closeとかもoverrideしないとランタイムエラーが出ると思いますので、 エラーが出たところから修正していきましょう。

なお、このあたりのコードはJava用なのでmutableに書いたほうが楽だと思われます。

import org.scalatest._

class UserSpec extends FlatSpec with Matches {
  "Sql" should "be checked by test Connection" in {
    val id = "kazzna"
    val query = "SELECT id, password, email FROM users WHERE id = ?"
    val map = Map(1 -> id, 2 -> "pass", 3 -> "email@example.jp")
    val expected = Some(User(map(1), map(2), Some(map(3))))
    val a = User.byId(id).transK[IO]
    val b = new QueryChecker(query, Map(1 -> id), new DummyResultSet(Seq(map)))
    val actual = a(b).unsafePerformIO
    actual should ===(expected)
  }
}

これでDB接続情報を一度も書かずにユニットテストができました!!簡単!!

例によって例の如くQueryにはCypherを使用していますが、 一応動くサンプルをgithubにあげておきました。

github.com

最後に: 教えて怖い人!

ConnectionIOOptionT[ConnectionIO, A]EitherT[ConnectionIO, String, A]なんかにして、 2つ3つ組み合わせて途中で失敗したら実行をやめるようなqueryを書くときに型引数つらいのですが、 なんとかなる方法はありませんか?

コメントお待ちしております(>﹏﹏<);;

以上でScala Advent Calendar 2015 12日目は終了です。
お付き合いいただきありがとうございます。

明日はOE_uiaさんによる「Scala AndroidかDeepLearning的な何か」です。
レベルが高そうですが、楽しみです。

今日から始めるScalaプログラミング!!


この記事はScala Advent Calendar 11日目です。

www.adventar.org

昨日はdakatsukaさんによるScalaでLuaスクリプトを動かして遊ぶでした。
Luaでしたね!!
ゲーム業界すごいですね!

さて、Scala Advent Calendarですが、まだまだ空きがあります。
難しいことを書かなきゃならないという空気を吹き飛ばすため、 Scalaをやったことのない人向けの記事を書くことによってハードルを下げます。

窓口が広いほど学びも増えるはずです!!

ということで本日はScalaを始めるための環境づくりです。

インストールせずに試す!!

オンラインならIDEONE

ideone.com

左下のChoose LanguageでothersのところにScalaがあります。
ライブラリーを使わないような入門書のコードなどは、ここで入力して試せますね。
もちろんLuaもあるのでLet's challenge!!

ローカルにScalaコーディング環境を構築する!!

ここからの説明は一番初心者向けということで、 Windows 10ユーザーを想定して進めます。

その他のOSの方はbrewなりportageなり環境にあったものをご使用ください。

Javaのインストール

ScalaJava VM上で動く言語です。
そのためまずはJavaのインストールが必要です。

JavaにはJavaで作られたプログラムを動かすためのJRE(Java Runtime Edition)と、 Javaでプログラムを作るためのJDK(Java Development Kit)があります。

今回はプログラミングを行うのでJDKですね。
JDKにはJREが含まれていますので、作ることも動かすことも可能です。

では、「JDK ダウンロード」などで検索してJavaダウンロードページにたどり着いてください。
プログラミングではGoogle力が試されることがよくありますので、 できる限り自力でたどり着くことが大切です。

f:id:kazzna:20151210221302p:plain

今回ダウンロードするのはJava SE(Standard Edition)のJDKです。 いろいろなJavaが出てきてもう挫折しそうですよね。
細かい名前は覚えなくてもあまりScalaには関係ありません。

さて、ダウンロードページにたどり着くと、さらに多数の選択肢が出て来ます。

f:id:kazzna:20151210222043p:plain

今回は最新版(数字が最も大きいもの)を導入します。 Java SE Development Kit 8u66ですね。
直接Java言語でプログラミングする予定はないので、DemosやSamplesはいらないでしょう。

ライセンスに同意しろと書かれているので、きちんとライセンスを読んだ上で、 同意できるならAccept License Agreementを選択します。

その下に並んでいるOSの一覧から、自分のOSを選択します。
WindowsにはWindows X86Windows x64がありますが、 自分のOSにあった方を選択してください。


x86x64かの確認方法

  1. Windowsのタスクバーの左端「Windowsマーク」を右クリックし、「システム(Y)」を選択します。
  2. 「システム」が開くので、真ん中ぐらいにある「システムの種類」を確認します。
  3. ここが「32ビット...」ならx86、「64ビット...」ならx64です。
  4. その他だった場合は自分でググってください。初心者用ではありません。

Edgeだと、ダウンロードが完了したらそのまま実行が選べます。

f:id:kazzna:20151211002247p:plain

インストールは何も考えずすべて「次へ」で大丈夫です。
インストールが終わったら、環境変数Pathにコマンドを追加します。

環境変数の編集はRapid Environment Editorというソフトが使いやすいらしいです。
使ったことはありませんが。

ここでは通常のWindowsの機能でPathを追加する方法を記述しておきます。
既にユーザー環境変数Pathが存在する場合は、この記事の下の方にある「パスに追加」を見てください。


パスを設定

  1. Windowsのタスクバーの左端「Windowsマーク」を右クリックし、「システム(Y)」を選択します。
  2. 「システム」が開くので、左端にある「システムの詳細設定」を選択します。
  3. 「システムのプロパティ」が開くので、詳細設定タブを選択します。
  4. 一番下の「環境変数」をクリックします。
  5. 上段の「ユーザー環境変数」の「新規」をクリックします。
  6. 変数名に「Path」、変数値に先ほどインストールしたJDKのパスを設定します。
    (インストール時にすべて「次へ」を選んでいれば「C:\Program Files\Java\jdk1.8.0_66\bin」です。)
  7. 順番にOKを押してウィンドウを閉じます。

インストールが完了したら、コマンドプロンプトを起動してインストールが成功したことを確認しましょう。
後からやると、どこで失敗したのかわからなくてリカバリーが大変です。

スタートメニューからコマンドプロンプトを起動します。
(同じくマークを右クリック -> コマンドプロンプト(C))
すると、下記のような表示の黒い画面が表示されるはずです。

C:\Users\kazzna>

kazznaの部分はログインしているユーザーのユーザー名になっているはずです。
この部分は勝手に出てくるので、>より後ろを入力してエンターを押すと入力した内容が実行されます。

さて、インストール成功かどうかの確認です。
こういう場合、普通はversionオプションを使用します。
javaではなくjavacなことに注意してください。

C:\Users\kazzna> javac -version
javac 1.8.0_66

version番号が表示されれば成功です。

versionオプションは「バージョン番号を表示して終了する」という動作をするプログラムがほとんどなので、 インストールされているかどうかを悪影響なく確認できます。

自分がプログラムを作るときもそういう風にするといいと思います。

javac -versionを実行してもバージョンが表示されずエラーメッセージが出たら?
Javaのインストールの初めからやり直すしかありません。

Activatorのインストール

Scalaでよく使われるツールsbtがあります。
sbtを使うと、ライブラリーのインストールやコンパイル・テストなどが簡単にできます。

今回はsbtにいろいろな機能を追加したActivatorというツールを使用します。
Activatorは内部にsbtを使用している(らしい)ので、 sbtでできることはすべてActivatorでできるはずです。

まずは先程と同様に「sbt activator ダウンロード」等で検索して、 Activatorのダウンロードページにたどり着きましょう。

f:id:kazzna:20151210230052p:plain

ここでDOWNLOADを選べばWindowsではzipファイルがダウンロードされるはずです。
この記事を書いていて初めて知りましたが、sbtの500倍ぐらいのサイズですね。
何が入ってるんだろう???

これをどこか好きな場所に展開してください。
「どこか」と言われても初心者は困るでしょうから、 決められない人はコマンドプロンプト>より左に書かれているフォルダに展開してください。

展開したら、activator-dist-1.3.7というフォルダができるはずです。
後ろの番号はバージョン番号なので、もしかしたら新しいバージョンになっているかもしれませんが。
フォルダの中にactivator.batが入っていることを確認してください。

このフォルダのパスを環境変数に追加します。


パスに追加

  1. Windowsのタスクバーの左端「Windowsマーク」を右クリックし、「システム(Y)」を選択します。
  2. 「システム」が開くので、左端にある「システムの詳細設定」を選択します。
  3. 「システムのプロパティ」が開くので、詳細設定タブを選択します。
  4. 一番下の「環境変数」をクリックします。
  5. 上段の「ユーザー環境変数」にある「Path」をクリックして選択します。
  6. 「編集」を押すと新規作成と同じようなウィンドウが開きます。
  7. 既に入っている変数値の末尾にセミコロン「;」を追加した後、activator.batがあるフォルダのフルパスを追加します。
    (ユーザー名に注意して「C:\Users\kazzna\activator-dist-1.3.7」みたいなのを入れてください。)
  8. 順番にOKを押してウィンドウを閉じます。

コマンドプロンプトを一度閉じて、もう一度開きなおしてください。
そして、以下のコマンドを実行し、Activatorがインストールできたことを確認します。

C:\Users\kazzna> activator --version
~~ もしかしたら何行かのメッセージ ~~
sbt launcher version 0.13.8

バージョンが表示されれば成功です。

Activatorを使ってみよう!!

早速Activatorを使用してみましょう。

まずは作業用フォルダを作成します。

C:\Users\kazzna> mkdir activatorwork

C:\Users\kazzna> cd activatorwork

C:\Users\kazzna\activatorwork>

最初のコマンドmkdir(make directory)でactivatorworkというフォルダをC:\Users\kazznaに作成しました。
次のコマンドcd(change directory)で、直下に作成したactivatorworkフォルダに移動しています。
3行目で左側のフォルダ名が変わっていますね。ここが現在いるフォルダです。

では、まずactivator new フォルダ名で新しいプロジェクト用フォルダを作ってみましょう。 ここではフォルダ名はactivatortestとします。

C:\Users\kazzna\activatorwork> activator new activatortest
~~ 何行かのメッセージ ~~
Browse the list of templates: http://typesafe.com/activator/templates
Choose from these featured templates or enter a template name:
  1) minimal-akka-java-seed
  2) minimal-akka-scala-seed
  3) minimal-java
  4) minimal-scala
  5) play-java
  6) play-scala
(hit tab to see a list of all templates)
>

activator newを実行すると、どのテンプレートを使用するか確認されます。
テンプレート一覧をダウンロードするため、少し時間がかかるかもしれません。

tabを押すと全てのテンプレートの一覧が表示され、名前か番号を入力すると次に進みます。
今回は4と入力してminimal-scalaを使用しましょう。

> 4
OK, application "activatortest" is being created using the "minimal-scala" template.

To run "activatortest" from the command line, "cd activatortest" then:
/home/kazzna/tmp/activatortest/activator run

To run the test for "activatortest" from the command line, "cd activatortest" then:
/home/kazzna/tmp/activatortest/activator test

To run the Activator UI for "activatortest" from the command line, "cd activatortest" then:
/home/kazzna/tmp/activatortest/activator ui

C:\Users\kazzna\activatorwork>

これでactivatorworkフォルダにactivatortestフォルダーが作成されました。
cdコマンドで移動してください。

C:\Users\kazzna\activatorwork> cd activatortest

C:\Users\kazzna\activatorwork\activatortest>

ここからはコマンドプロンプトはこのまま開いたままで、エクスプローラーで作業しましょう。
コマンドプロンプトが得意な方はこのまま作業していただいても構いません。

エクスプローラーを開いたら、アドレスバーにコマンドプロンプト>より左の部分を貼り付けてください。

f:id:kazzna:20151210233823p:plain

ちなみに、コマンドプロンプトからのコピーは

  1. 右クリック -> 範囲指定
  2. 左ドラッグで文字を反転
  3. キーボードでエンターキーをたーんっ!

です。ご注意ください。

f:id:kazzna:20151211003948p:plain

フォルダを開くと、ここにもactivator.batなどがあるのがわかりますね。
Activatorをインストールしていない人でもプロジェクト途中から参加できるように、なのでしょうか?

ファイルがおっきいので、ここのactivatorから始まるやつは全部消してOKだと思います。

さて、この中身の説明です。

  • build.sbt
    sbtの設定ファイルです。ここにいろいろ書くことでライブラリーやコンパイルオプションなどを変更できます。
  • project
    このフォルダの中にsbt自身の設定やsbt用のプラグインの設定を書きます。
    今回の記事では触りません。
  • src
    この中に自分で作るプログラムのソースコードを置きます。
    Activatorコンパイルしてくれます。 srcの中には以下のようなフォルダがあります。
    • main
      プログラム本体のコードを格納します。
      この中にはデフォルトで次の3種類のフォルダを配置できます。(プラグインで拡張可能)
    • test
      プログラムをテストするためのコードを格納します。
      こちらもmainと同じフォルダが作成可能です。

srcmainにあるHelloworld.scalaをメモ帳などで開けばもうコーディングが可能ですね。

さて、Activatorを使ってコンパイルしてみましょう。
コマンドプロンプトに戻ります。

C:\Users\kazzna\activatorwork\activatortest> activator compile
~~ 何行か表示 ~~
[success] Total time: 124 s, completed 2015/12/11 1:01:27

初回の起動のみ、いろいろなファイルをダウンロードしてくるので時間がかかると思われます。

次は実行です。

C:\Users\kazzna\activatorwork\activatortest> activator run
~~ 何行か表示 ~~
[info] Running com.example.Hello
Hello, world!
[success] Total time: 0 s, completed 2015/12/11 1:02:18

同様にテストを実行。

C:\Users\kazzna\activatorwork\activatortest> activator test
~~ 何行か表示 ~~
[info] HelloSpec:
[info] Hello
[info] - should have tests
[info] Run completed in 375 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 6 s, completed 2015/12/11 1:02:54

ライブラリーを使う

ライブラリーを使いたいときはbuild.sbtを編集します。 たとえば、MySQLへ接続するためのmysql-connector-javaを入れたいときは、`以下の記述を追加します。

libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.37"

Scalajsonを扱うためのjson4sならこんな感じです。

libraryDependencies += "org.json4s" %% "json4s-native" % "3.3.0"

Scalaのライブラリーは%%Javaのライブラリーは%です。
なぜそうなってるのかは気になったらググってください。

このlibraryDependenciesに追加したライブラリーは、 ローカルに無ければ次回のコンパイル時などに自動的にダウンロードされます。

他にもいろいろ機能がありますので、「sbt 使い方」で検索してください。
出てきたコマンドのsbtをそのままactivatorに変えると動くはずです。

IDEを使ってみよう!

さて、ここまでの内容で既に書いて・コンパイルして・テストして・実行はできるわけですが、 最後にIDEをひとつご紹介しておきます。

www.jetbrains.com

有料のUltimateと無料のCommunityエディションがありますが、趣味で使う分にはCommunityで十分です。
仕事で使う場合はライセンスを確認してください。

このIDEA(アイディア)さん、 なんと先ほどActivatorで作ったプロジェクトをそのまま読み込んで作業できるのです。
設定したライブラリーなども自動で取得してくれます。

sbt-ideaなんていうsbtプラグインもありますが、使わなくても動くので使っていません。

詳しいインストールなどについてはサムライズムさんのブログなどをご参照ください。


Scala Advent Calendar 11日目は以上です。
お付き合いいただき、ありがとうございました。

これを見て「この記事よりかはいいものを書けるぜ!」と思ったあなた!
今すぐカレンダーの空きを埋めるのです!!Qiita版も空きがありますです!!

明日も2日連続で私による「いちばんゆるふあななにかを」です。

まだ何を書くのかを決めていませんが、とにかく「ゆるふあ」に行きます!
まだ決まってないので遅い時間になるかもです。。。すみません。