zephiransasのチラシの裏

とあるJava/Rubyプログラマのメモ代わりブログ

JavaプログラマがKindle50%還元セールで買っておくべきIT技術書

Kindle Storeでセールをやってるようです。今回は50%をポイント還元するってセールらしいです。

で、こちらを見てたらRubyやPHPはあっても、Javaがなかったので、ついカッとなってJavaプログラマ向けのオススメ技術書をチョイスしました。 セールは6/1の正午までですので、お早めにどーぞ。

これは店頭で目次を見た程度です。わりと初心者向けな印象なので、これからJavaを勉強したい人にオススメです。

いわずと知れた「パーフェクトシリーズ」のJava版。広範囲に網羅されているので、手元に置いておけば長く使えると思います。初心者でも可。

これも「逆引きレシピシリーズ」のJava版。リファレンス的に使うのならコイツは鉄板。

そもそもJava EEの日本語の本は少ないのですが、最新のJava EE7に対応した本。

1つ前のバージョンであるJava EE6の本。通称「金魚本」。Java EE6と多少古くはあるがJava EE7と全然違うというわけでもないので、未だに現役で使えるはず。内容はある程度Java EE6の仕組みを理解している人がリファレンス的に使う感じだと思います。

現場からは以上です。

Project Kullaを試す

以前から気になっていたJavaのREPL、Project Kullaを動かしてみました。

REPLとはRead-eval-print loopの略で、CUIからコードを直接入力していって、その場で動作を確認できるツールです。 Rubyであればirbやpryなどが有名ですね。

Project KullaはOpenJDKにて開発されている、JavaのREPL環境をつくるプロジェクトです。 ちなみにこの機能はJDK9で、正式導入される予定になっています。

JLine2のインストール

早速REPL環境を動かしてみたいところですが、まずは前準備として、Kullaに必要なJLine2というライブラリをビルドします。

ソースコードはGitHubのリポジトリでホストされていますので

1
2
3
git clone git@github.com:jline/jline2.git
cd jline2
mvn install

ちなみにJLine2はJDK8以前でないとビルドできないので注意です。

ビルドに成功するとjline2/targetディレクトリにjline-2.13-SNAPSHOT.jarが作成されます。Kullaからは、このjarを利用します。

JDK9 EAのインストール

KullaのビルドにはJDK9が必要です。こちらからJDK9をダウンロードし、インストールします。 自分がインストールしたのは、以下のバージョン。

1
2
3
java version "1.9.0-ea"
Java(TM) SE Runtime Environment (build 1.9.0-ea-b59)
Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b59, mixed mode)

その後、使用するJAVA_HOMEをJDK9に設定します。

普段、自分はJAVA_HOMEの設定にjava_homeコマンドを使用しているので、.bash_profileに

1
export JAVA_HOME=`/usr/libexec/java_home -v 1.8`

としてJDK8を使用しています。今回はJDK9を使いたいので、これを

1
export JAVA_HOME=`/usr/libexec/java_home -v 1.9`

とし

1
source ~/.bash_profile

として、JDK9を有効にします。

Kullaのビルド

いよいよKullaのソースをダウンロードしてビルドします。

1
2
hg clone http://hg.openjdk.java.net/kulla/dev ~/kulla
cd ~/kulla

次に、その他必要なソース類を取得します。

1
2
chmod 755 get_source.sh
./get_source.sh

しばらく待つと、終了します。次にビルドスクリプトを環境に合わせて修正します。

1
cd langtools/repl

scripts/compileを以下のように修正します。

scripts/compile
1
2
3
4
5
6
#!/bin/sh
JLINE2LIB=/Users/[ユーザ名]/jline2/target/jline-2.13-SNAPSHOT.jar
JAVAC_BIN_HOME=/Library/Java/JavaVirtualMachines/jdk1.9.0.jdk/Contents/Home/bin

mkdir -p build
$JAVAC_BIN_HOME/javac -Xlint:unchecked -Xdiags:verbose -cp ${JLINE2LIB} -d build src/*/*.java

1行目 - OSXの環境に合わせて"#!/bin/sh"に修正 2行目 - jline2のjarを指定 3行目 - JDK9のjavacのあるディレクトリを指定 6行目 - 先頭に"$JAVAC_BIN_HOME"を追加

修正できたら

1
scripts/compile

でビルドしましょう。なにもエラーがでなければ、成功しています。

REPLを実行する

実行前にscripts/runを以下のように修正します。

scripts/run
1
2
3
4
#!/bin/sh
JLINE2LIB=/Users/[ユーザ名]/jline2/target/jline-2.13-SNAPSHOT.jar
JAVA_BIN_HOME=/Library/Java/JavaVirtualMachines/jdk1.9.0.jdk/Contents/Home/bin/
$JAVA_BIN_HOME/java -ea -esa -cp build:${JLINE2LIB} tool.Repl "$@"

先になおしたスクリプトとほぼ同じです。

修正できたら、早速実行してみましょう。

1
scripts/run

すると、以下のようにプロンプトが表示されます。

1
2
3
4
|  Welcome to the Java REPL -- Version 0.411
|  Type /help for help

->

あとは普通にJavaのプログラムが書けます!

1
-> System.out.println("Hello!");

また、CUIなどと同じようにタブによる補完もできます。

Shift + Tab補完もなかなかステキ。

当然ですがクラスを定義することもできます。

1
2
3
4
5
6
7
8
-> class Hoge {
>> public static String fuga(){ return "FUGA!!"; }
>> }
|  Added class Hoge

-> Hoge.fuga();
|  Expression value is: "FUGA!!"
|    assigned to temporary variable $1 of type String

面白いのは、いきなりメソッド定義もできます!

1
2
3
4
5
6
-> int add(int x, int y){ return x + y;}
|  Added method add

-> add(2,3);
|  Expression value is: 5
|    assigned to temporary variable $2 of type int

普通に使えそうですね!

またTab補完周りの機能については、我らの@bitter_foxくんが実装に関わってるらしいので、補完機能が怪しかったら、ぜひレポートしてあげてください。

参考にしたリンク

GitHubのPull requestから、CHANGELOGっぽいものを作成するgemを作った

gemを作りました。名前はoctocamです。

主な機能としては「GitHubから指定された日付期間にマージされたPull requestを抽出し、CHANGELOGっぽいMarkdownを生成する」というgemです。

定期的にリリースを行っている場合に、以前リリースされたときからどのような機能が増えたかをCHANGELOGとかに書き出しますが、そういった時に便利に使えると思います。

似たような機能を持つものはgemやnpmを探すと、結構あります。この辺りとか。ただ、いずれも

  • 日付の指定ができない。できたとしてもPull requestの作成日とか。
  • issueやcommitを含めてしまう。
  • Markdownで出力できない。
  • 認証に対応してない。

などなど、要求を満たすものではなかったので、gemの作り方を勉強がてら作ってみました。

ワークフローとして、 必ずPull requestでレビューをしてから、マージをおこなうワークフロー を採用しているところであれば、フィットするように思います。

インストール

以下のようにしてインストールします。

1
2
gem install octocam
rbenv rehash  # rbenvを使ってる人はrehash

もしプライベートなリポジトリにアクセスしたい場合は、こちらからPersonal access tokensを生成します。 あとは、生成したトークンを.bash_profileあたりから、環境変数「OCTOCAM_GITHUB_TOKEN」に設定しておきます。

1
export OCTOCAM_GITHUB_TOKEN="your-40-digit-github-token"

使い方

インストールされるとoctocamコマンドが使えるようになるので、以下のようにして実行します。

1
octocam -o zephiransas -r octocam -f 2015-01-01 -t 2015-01-31

-f,-tオプションにPull requestがマージされた日付を指定でききます。

カレントディレクトリがgitのローカルリポジトリで、かつ、originがGitHubに設定されている場合であれば-o,-rオプションは省略できます。

欲しい機能ありましたら、issueを立てて頂くか、Pull requestを投げてください。

Lambda-behaveでテストを書こう

これはJavaアドベントカレンダー2014の12/16分の記事です。

昨日はgrimroseさんの、[書評] Gradle徹底入門 でした。

明日は@com4dcさんの、はじめて触るStreamの世界 です。

自分はJavaのテストフレームワークである、lambda-behaveについて紹介します。

自分は普段はRailsでの開発を行っているのですが、現場では主にRSpecを使ってテストを記述しています。RSpecでのテストは以下のような感じです。

1
2
3
4
5
6
7
describe 'Sample' do
  context 'hogeメソッドについて' do
    it 'fugaを返すこと' do
      Sample.hoge.should == "fuga"
    end
  end
end

RSpecでは上記のようにDSLを使って、なにをテストしているかを構造的に記述することができます。 lambda-behaveを使うと、このようなDSLっぽい記述のテストを、Java8のLambdaを使って書くことができるようになります。

最初のテスト

まずはテスト対象となるメソッドを準備します。

1
2
3
4
5
public class Sample {
    public static int includeTax(Integer price) {
        return 0;
    }
}

上記のようなstaticなメソッドを準備します。includeTaxメソッドは引数を一つ取り、その税込み金額を返すメソッドとします。実にギョーミーですね!

今回はTDD的なノリで実装していきますので、ここでは中身の実装はおこないません。

それでは実際のテストを書いて行きましょう。ここでのテストシナリオは

  • includeTaxメソッドに100を渡した場合に、108が返ってくること

をテストするとします。これをlambda-behaveで書くと、以下のようになります。

1
2
3
4
5
6
7
8
9
10
import static com.insightfullogic.lambdabehave.Suite.*;

@RunWith(JunitSuiteRunner.class)
public class SampleSpec {{
    describe("includeTax", it -> {
        it.should("税込み価格が取得できること", expect ->
            expect.that(Sample.includeTax(100)).is(108)
        );
    });
}}

static importを使ってlambda-behaveのメソッドを使えるようにし、こられを使って記述していきます。

JUnitのランナーも用意されていますので、これを@RunWithで指定すれば、IDEからも簡単にテストを実行可能です。早速、テストを実行してみましょう。

screen1

includeTaxは、まだ実装をおこなっていませんので、当然このとおりテストが失敗します。

次に、includeTaxを実装してみます。

1
2
3
4
5
6
public class Sample {
    public static int includeTax(Integer price) {
        final float TAX_RATE = 0.08;
        return (int)Math.floor(price * (1 + TAX_RATE));
    }
}

再度、テストを実行すれば、テストが成功しています。

screen2

複数のテストデータでチェック

先の例では1つの値でしかテストしませんでしたが、lambda-behaveでは同時に複数の値でテストすることもできます。以下のようになります。

1
2
3
4
5
it.uses(100, 108)
  .and(200, 216)
  .toShow("税込み価格が取得できること", (expect, price, includeTax) -> {
     expect.that(Sample.includeTax(price)).is(includeTax);
  });

itのあとにuseとandをチェインして値を準備し、これを使ってtoShowメソッド内でテストを行います。toShowメソッド内ではlambdaの引数で準備した値を利用できますので、lambda内でその値をexpectするようにしています。

生成した値でチェック

lambda-behaveではランダムな値を生成する機能も準備されています。適当な数値を5つほど生成して、そのテストを行うコードは以下のようになります。

(あまり例がよくないですが・・・)

1
2
3
4
5
it.requires(5)
  .example(Generator.integersUpTo(1000))
  .toShow("税込み価格が取得できること", (expect, price) -> {
    expect.that(Sample.includeTax(price)).is((int)Math.floor(price * 1.08));
  });

requiresでランダムに準備する値の数を指定します。

exampleではどのようなテストデータを生成するかを指定します。ここではlambda-behaveで準備されたGenerator.integersUpToを使用しています。この他にも適当な文字列を生成するasciiStringsメソッドなどもあります

例外が発生することをチェック

引数にnullが渡された場合にNullPointerExceptionの発生をチェックすることも、JUnitと同様に可能です。

まず、includeTaxにnullチェックを記述します。

1
2
3
4
5
6
7
8
9
public class Sample {
    public static int includeTax(Integer price) {
        if(price == null) {
            throw new NullPointerException();
        }
        final float TAX_RATE = 0.08f;
        return (int)Math.floor(price * (1 + TAX_RATE));
    }
}

これをテストするlambda-behaveのコードは以下のようになります。

1
2
3
4
5
it.should("nullの場合ぬるぽ", expect -> {
    expect.exception(NullPointerException.class, () -> {
        Sample.includeTax(null);
    });
});

exceptionメソッドの第1引数に、発生する予定の例外を指定し、第2引数には例外が発生する処理をlambdaで記述します。

lambdaに慣れていないと少々書きづらいかもしれないですが、DSLちっくに書けるのはJavaっぽくなくてステキですよね!

こちらからは以上です。

JJUG CCC 2014 Fallで発表してきた

11月15日に、東京は新宿の西新宿ベルサールにて開催されたJJUG CCC 2014 Fallに参加してきました。

JJUC CCC(クロス・コミュニティ・カンファレンス)日本Javaユーザ会が春/秋と、年に2回開催している、JJUG主催としては最大のイベントです。

今回はこれのセッション公募(CfP)に応募したところ嬉しい事にセッション枠を1つ受け持つことになったので、それも兼ねて東京まで参加してきました。 久々に東京のJavaコミュニティの勉強会で、普段はTL上でしか面識のない人たちに会えるのも、楽しみの一つ。

いつもの面々(失礼)もそうですが、今回は以前からお会いしたいと思っていた @kikutaro_ さんと、お昼をご一緒させていただくことができました。TL上での発言を見て「真面目な好青年っぽいなー」という印象を持っていましたが、会ってもやはり好青年でした。

普段から何をツイートするか、考えて発言しないといけませんね!! (ゲフンゲフン

それから余談ですが、実は大都会ITクラスタは過去、JJUG CCCのスピーカを3人輩出しています。

最初は独立国家福山に住む「@soudai1025 氏」

それから岡山Javaユーザ会/倉敷天領Scala勉強会に所属する「@razon 氏」

あとは「@mao_instantlife 氏」

他の地方で、これだけスピーカが出てるところはないように思うので、ちょっと自慢していいような気もしますw

自分のセッションについて

今回自分はRailsライクなWebフレームワーク「ninjaframework」について、セッションを行いました。以下はその資料。

一番小さい部屋だったので、おそらく40~50人程度の方がいらしていたと思います。

当日、他のセッションでSpring Bootのセッションとハンズオンがあり「これはネタを選択し間違えた感・・・」と思ったのは内緒。

久々の発表だったり、資料作りが思うように進まなくて、練習もろくにできなかったりで、たどたどしいことこの上ないセッションになってしまったような気がします・・・

しかも50分の予定が40分程度で終わってしまい、困ったなーと思っていたところ、Q&Aで意外にも多くの方から質問を頂きました。その結果、きっちり50分!

あまりうまくいかなかった部分もありましたが、最後まで聞いていただいた皆さん、大変にありがとうございます!

Java女子部の台頭

以下はセッションの内容とはあまり関係ない、参加して自分が肌で感じたことです。

今回のCCCで一番思ったことが、女性の参加者が多いこと。

個人的にですが、エンジニアの世界はまだまだ男性中心な世界だなと感じていて、女性でバリバリコード書いたり、勉強会で発表してる人って少ないのが現状です。(それが良いとも悪いともいいません。それは本質ではないので。)

なので、今回のCCCに多くの女性エンジニアがいたことには正直驚きました。最近、女性エンジニアの有志を中心に「Java女子部」なるコミュニティが発足したことは知っていましたが、それが広まってきてる感じです。

エンジニアという職業が成熟していく過程に、女性が活躍できる環境というのは必須だと思います。また、それがエンジニアという仕事を一生の仕事にするためにも、必要なことだと思います。

Javaコミュニティの復活の兆し

つい先日発売された「Javaエンジニア養成読本」(通称「妖精本」)の巻頭記事に、Javaのコミュニティの歴史について触れている部分があります。

自分がJavaのコミュニティに最初に触れたのは、Seasarが流行っていた時代です。

その後Javaのコミュニティは、Sunの不振などもあり少しづつ勢いを失ってきたように思います。

しかし今回のCCCの参加登録数は約650名で過去最高。また懇親会の参加者も受付開始するとあっという間に満席になり、最終的には100名とこちらも過去最高。自分にとっても最高に楽しい時間でした。

これもひとえに2007年4月にJJUGが発足以来、地道に活動してこられた多くの人たちの努力の賜物です。

自分が感じたことは、Javaコミュニティは再びかつての勢いを取り戻しはじめている、ということです。

そして言語としてのJavaもJava8で導入されたLambdaを皮切りに、これからも進化を続けていって欲しいと思います。

Pusherを使ったChrome拡張を作る

メッセージ等の新着通知やアップデート情報の配信など、アプリケーションへの通知の方法として、スマートフォンなどで使われるpush通知など、最近では様々なものがあります。

しかし自前で通知用のサーバを運用するのは手間がかかるので、これを簡単に使えるようにするサービスも増えてきました。例えばPusher.comなどがあります。これを使うことで、ブラウザへのリアルタイムな通知機能を、WebSocketを使って簡単に作成することができます。

pusher-ss

今回はPusherからの通知をChrome拡張で受信し、これをデスクトップ通知するサンプルを作成しましたので、解説してみます。

Pusher側の設定

まずはPusher側に設定を行います。Pusherでアカウントを作成後、以下のようにアプリケーションを登録します。

pusher1

ここでEncryptionにチェックを入れておきましょう。チェックしなくても特に問題はないのですが、Chrome拡張の場合セキュリティの問題からSSLを使用したほうが、いろいろ都合がいいので、チェックするほうが無難です。

Chrome拡張の作成

manifest.jsonの設定

manifest.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
    "manifest_version": 2,
    "name": "Pusher test extension",
    "version": "0.0.1",
    "description": "Pusher用 Chrome extension",
    "permissions" : [
        "notifications"
    ],
    "content_security_policy": "script-src 'self' https://stats.pusher.com; object-src 'self'",
    "background" : {
        "scripts": [
            "src/javascript/pusher.min.js",
            "src/javascript/background.js"
        ]
    }
}

今回はPusherからのメッセージをデスクトップ通知するようにしたいのでpermissionに

1
2
3
"permissions" : [
    "notifications"
],

を指定しています。

また、content_security_policyのscript-srcに https://stats.pusher.com** を追加しています。httpではなくhttps**を指定していることに注意してください。

1
"content_security_policy": "script-src 'self' https://stats.pusher.com; object-src 'self'",

このサイトは、Pusherのクライアントライブラリであるpusher.min.jsからアクセスしているのですが、これを許可していないとChrome拡張からPusherのサーバへ、正しく接続をすることができません。

次にpusher.min.jsですが、これは本来であればPusherのサイトに公開されているものを読み込んで使いたいところなのですが、Chrome拡張では外部のjavascriptを読み込むことができないようです。なので、ダウンロードしてソースに加えています。 ちなみにpusher.min.jsのホスト先は、こちらで公開されています。

background.js

あとはChrome拡張のバックグラウンドで実行されるbackground.jsで、Pusherとの接続を行います。

background.js
1
2
3
4
5
6
7
8
9
10
11
var pusher = new Pusher("======== KEY ========", { encrypted: true });
var channel = pusher.subscribe('test_channel');
channel.bind('my_event', function(data) {
  var opt = {
    type: 'basic',
    title: data.title,
    message: data.message,
    iconUrl: ""
  }
  chrome.notifications.create("", opt, function(id){ /** Do Nothing */ });
});

Pusherのコンストラクタに渡すkeyには、Pusherで作成したアプリケーションのKeyを指定します。

pusher2

また、大事なポイントとしてPusherのオプションに

background.js
1
{ encrypted: true }

を指定する必要があります。これは先のmanifest.jsonの設定でも触れましたが、この指定がない場合Pusherの接続先が **http://stats.pusher.com** となってしまいます。Chrome拡張ではhttpsでない外部サーバに接続することはセキュリティ上できませんので、上記のオプションを指定しています。

Chrome拡張の読み込み

では、このようにして作ったChrome拡張を、Chromeに読み込ませて動作確認してみましょう。

ChromeのURL欄に chrome://extensions/ と入力します。まだデベロッパーモードを有効にしていない場合は「デベロッパーモード」をチェックします。次に「パッケージ化されていない拡張機能を読み込む」をクリックします。

pusher3

そして先ほど作ったChrome拡張を含むディレクトリを指定します。すると、拡張機能の一覧に表示されます。

pusher4

これでChrome拡張を導入することができました。

Pusherからテストを行う

それでは実際にPusherから通知を行い、Chrome拡張に通知が表示されるかどうか確認してみましょう。

Railsなどを使って自分でサーバアプリを作ってもいいのですが、今回はPusherのEvent Creatorの機能を使ってみましょう。

Pusherの管理画面から「Event creator」を選択し、以下のように入力します。

pusher5

これで、Send eventボタンをおして、うまくいけば画面に以下の様な通知が表示されます。

pusher6

今回はアイコン画像のURLを指定しなかったので、なにも表示されていませんが、以下の用に画像へのURLを指定することでアイコンを表示することもできます。

background.js
1
2
3
4
5
6
var opt = {
  type: 'basic',
  title: data.title,
  message: data.message,
  iconUrl: "http://example.com/path/to/icon"
}

ソースなど

今回作成したChrome拡張は、こちらのGithubにまとめてあります。参考にしてみてください。

岡山の勉強会に参加する際の心構え

IT勉強会はなにも東京ばかりで開催されているわけではない。

地方の勉強会に参加するのであれば、ついでに観光地を巡ったり、その土地の美味しいモノを食べたいというのが人情である。

本エントリでは岡山の勉強会に来た際に食べるべきものを紹介する。

もも、ぶどう

言わずと知れた岡山の特産品。桃は白桃、ぶどうはマスカット・オブ・アレキサンドリアなどが有名。なにしろ倉敷にはその名もマスカット球場なるスタジアムがあり、楽天の星野仙一監督が倉敷出身という縁もあり、ここ数年は楽天がキャンプをやってたりする。それぐらい有名。ただし、どれもそこそこお値段がするので、お財布に余裕があるときにしましょう。

また、ちょっと亜流ではあるけれども白桃やマスカットを和菓子で食すという方法もある。岡山には源吉兆庵なる和菓子屋さんがあり、これは世界的にも有名。サンフランシスコにも出店してたりする。ここのお菓子に「桃泉果」なるものがあり、これは白桃をまるまる一つ使った贅沢な逸品。マスカットであれば「陸乃宝珠」というものがあります。これはこれで美味しいので、おすすめです。ただし、どれもそこそこお値d(ry

牡蠣&牡蠣おこ

oister

日生であれば、なにをおいても牡蠣です。日生で牡蠣を食べたいのであれば五味の市がおすすめです。ここでは1kgから殻付きの生牡蠣を買うことができます。これを五味の市近くにある道の駅で、BBQにしていただくのが定番です。シーズン中の牡蠣は身も大きく、とても美味しいですよ。

詳細はこちら

また、B級グルメとしても定番になった感のあるカキオコも日生ではよく見かけます。これも押さえておきたい。

えびめし

えびめし

岡山の誇るB級グルメ「えびめし」

海老の入った、デミソース風味の焼き飯とでも言った感じ。

岡山には「えびめしや」なるレストランが数店あり、地元民も愛する味。

他にも、市の中心部からほど近い、天満屋バスターミナルの地下にある「いんでいら」のえびめしもオススメ。

個人的には、かつて岡山市倉田にあった「いんでいら」がイチオシ。自分が小さい時から慣れ親しんだ味だったが、残念ながらマスターが高齢になったこともあり、今は閉店してしまった。しかしここのえびめしこそが岡山の元祖えびめしとおもっている

パフェ

意外かもしれないが、岡山といえばパフェ。こんなページもあったりするぐらいに推してる。

そして、Java会の重鎮、櫻庭さんも岡山のパフェ推しで有名。大都会アドベントカレンダーでも、岡山のパフェを紹介して頂いています。

後楽園

廉池軒

倉敷の環境名所といえば「倉敷美観地区」ですが、岡山の観光名所といったら「後楽園」

江戸時代、岡山藩藩主池田綱政によって造成された、日本庭園です。いまでも園内には、古い建物が残っており、これを一般市民でも有償で利用することができます。こんな素晴らしい庭園で、のんびり勉強会とかできたらいいですよね?

・・・

・・・

・・・

というわけで、この後楽園でJava8のハンズオンを企画しました!

ぜひ、この機会に岡山にお越しいただき、岡山の美味しいものと、美しい風景を堪能してはいかがでしょうか?

皆様のご参加をお待ちしております。

あわせて読みたい

Java8で始めるLambda(基礎編)

まもなくリリース予定のJava8。その中でも最も大きなインパクトを持つというProject Lambdaについて、ここ数日調べてみました。 今からLambdaをはじめようとする人向けに、何回かに分けてまとめてみたいと思います。

インターフェースの宣言

まずは手始めに、引数で指定された文字列の前後に"[“と”]“をつける処理を考えてみましょう。

Lambdaを使用するには、まずインターフェースを宣言する必要があります。上記の仕様から考えると

  • 引数はString型の引数が1つ
  • 戻り値もString型

となるので、この場合は以下の様なインターフェースを宣言します。

LambdaInterface.class
1
2
3
public interface LambdaInterface {
  String method(String value);
}

ここで注意するべきことが1つ。Java8のLambdaとして使えるインターフェースには決まりがあるのですが、もっとも重要なのがインターフェースのメソッドが1つだけということです。インターフェースのメソッドが2つ以上ある場合には、それをLambdaとして使用することはできません。

これはLambdaの実装部分を書く際に、どのメソッドの内容を実装しているのかを書かないため、Lambdaを書いた場合はそのインターフェースがもつ唯一のメソッドに対して実装をおこなったとみなすからです。

一見、これは不便なように思ってしまうかもしれないですが、普段使うパターンのインターフェースのほとんどがjava.util.functionパッケージ内で用意されているので、実際にはそれ程不便ではありません。むしろ自分でインターフェースを用意するほうが稀かもしれません。

Lambdaを使った記述

早速、先に宣言したインターフェースを使ってLambdaを書いてみましょう。Lambdaを記述する際の基本となる文法は、以下のようになっています。

1
2
3
[インターフェース名] [lambda式の名前] = (引数の型 引数,...) -> {
  (実装)
};

よってLambdaInterfaceを使って書くと、以下のようになります。

Sample.class
1
2
3
4
5
6
7
8
9
10
public class Sample {

  public static void main(String... args) {
    LambdaInterface lambda = (String value) -> {
      return "[" + value + "]";
    };
    System.out.println(lambda.method("HOGE"));
  }

}

実行すると"[HOGE]“と出力されていることがわかると思います。

このように、匿名クラスを使った場合などと比べて、少ない記述量で実装できると思います。

Lambdaの省略記法

また、このLambdaの記述では、以下のルールで、省略した記述を使用することもできます。

  • 引数の型は(型推論できるので)省略できる
  • 引数が1つの場合は、引数の()を省略できる
  • 但し、引数なしの場合は省略できない
  • 実装部分が1行の場合は、{}を省略可能。さらにreturn文も不要

上記ルールに沿ったLambdaであれば省略可能です。ですので先ほどのコードも以下の様に省略できます。

Sample.class
1
2
3
4
5
6
7
8
public class Sample {

  public static void main(String... args) {
    LambdaInterface lambda = value -> "[" + value + "]";
    System.out.println(lambda.method("HOGE"));
  }

}

かなりスッキリしましたね!

java.util.functionで提供されるインターフェースを使う

先ほど少し触れましたが、上記のLambdaInterfaceのような普段Lambdaとして使うインターフェースはjava.util.function内にいろいろ用意されています。 例えば、LambdaInterfaceの様に「String型の引数を1つ取り、String型の戻り値を持つ」インターフェースはjava.utl.functionパッケージ内にあるFunctionインターフェースを使います。

Sample.class
1
2
3
public interface Function<T, R> {
  R apply(T t);
}

最初の型引数Tには1つ目の引数の型、2つ目の型引数Rには戻り値の型を指定します。またapplyメソッドが実装対象となるメソッドです。

先のコードをFunctionインターフェースを使って書き直すと。

Sample.class
1
2
3
4
5
6
7
8
public class Sample {

  public static void main(String... args) {
    Function<String, String> lambda = value -> "[" + value + "]";
    System.out.println(lambda.apply("HOGE"));
  }

}

となります。Functionの他にも

  • 引数を1つ持ち、戻り値がないConsumer
  • 引数がなく、戻り値があるSupplier
  • 引数を1つ持ち、戻り値がboolean型のPredicate
  • 引数を1つ持ち、かつこれが戻り値と同じ場合のUnaryOperator

などのインターフェースが提供されています。

どういった場合に、どのインターフェースを使えばよいかについては、Qiitaにまとめておきましたので、参考にしてみてください。

通常は、ここで提供されているインターフェースを使い、それ以外のパターンが発生した場合のみ、自分でインターフェースを宣言するほうがよいでしょう。

メソッド参照を使う

メソッド参照もJava8で新しく追加された機能です。

メソッド参照を使うと、他のクラスのクラスメソッドやインスタンスメソッドを、Lambdaの実装として利用することができるようになります。メソッド参照はドット(.)でメソッドを呼ぶ代わりに、コロン2つで呼び出します。

Sample.class
1
[クラス名]::[メソッド名]

例えば先の文字列の前後にカッコをつけるメソッドが以下のようにSampleクラスのstaticメソッドとして定義されていた場合

Sample.class
1
2
3
4
5
6
7
8
9
10
11
public class Sample {

  public static void main(String... args) {
    ...
  }

  private static String add(String value) {
    return "[" + value + "]";
  }

}

Sample.addをメソッド参照するには

Sample.class
1
2
3
4
5
6
7
8
9
10
11
12
public class Sample {

  public static void main(String... args) {
    Function<String, String> lambda = Sample::add;
    System.out.println(lambda.apply("HOGE"));
  }

  private static String add(String value) {
    return "[" + value + "]";
  }

}

ここではstaticなクラスメソッドを使いましたが、インスタンスメソッドの場合も同様に、インスタンスを生成し、そこからメソッド参照をすることができます。

Sample.class
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Sample {

  public static void main(String... args) {
    Sample sample = new Sample();
    Function<String, String> lambda = sample::add;
    System.out.println(lambda.apply("HOGE"));
  }

  public static String add(String value) {
    return "[" + value + "]";
  }

}

Photo Leafをちょっとリニューアルしました

前から気になっていたPhoto Leafのフォトブック作成画面のリニューアルをしました。

フォトブック編集画面

画面の中央部分にフォトブックのページ一覧。画面の一番下に、flickrの写真一覧を表示するようにしました。今までとは、真逆のレイアウトになっています。

  • flickrの写真一覧は左右のスライダーでページを移動できます。
  • ちなみに、スクロールする度にPhotoStreamの写真を逐次読み込む仕様になっています。
  • flickrの写真は、クリックすることで大きめの画像を画面中央に表示できます。
  • Set内の写真のみを一覧に表示した場合は「Setを選ぶ」ボタンを押すことで、Setを選択できます。

写真選択は今まで通り、ドラッグ&ドロップでフォトブックの各ページに写真を置いていきます。

flickrに写真を保存していて、フォトブックを作ってみたい方は是非ご利用ください。

技術的なこと

ついでといってはなんですが、裏側もちょこちょこ修正しています。

  • unicornを使うようにした。多少はパフォーマンスがあがってる(はず)
  • werckerを使って、masterにpushするだけで、あとは自動でテスト->デプロイまでできるようにした。
  • 利用規約のページなど、他とは微妙に違うページは別layoutにしてたのを、content_forを使ってapplication.html.erbに一本化した。
  • rpsecのテストにshoulda matcherを導入した。

といったとこです。特にwerckerは素晴らしい。 werckerのお陰で、本番環境とステージング環境をあまり考えることなく、テストからデプロイまでやってくれるのは、非常に楽でした。

このあたりのwerckerの使い方も、後ほどまとめてみようかと思っています。

werckerでrspecとcucumberのCI環境を作る

去年作ったPhoto LeafというWebサービスがあるのですが、これのCI環境を作成したいなぁと思っていたところwerckerというCIサービスを使って構築できたので、そのまとめです。

werckerとは?

werckerTravisCIなどに代表されるように、外部でビルド(というかテスト)やデプロイを行ってくれるCI(継続的インテグレーション)サービスです。

使い方としては、リモートリポジトリに変更がpushされた時点でこれをフックして、CIサービス側でテストしたり、場合によってはそのまま本番環境に自動デプロイとかもしてしまえば、変更内容を安全、かつ迅速にリリースできる仕組みが出来上がるわけです。イマドキっぽいですね!

werckerの特徴としては

GithubとBitbucketに対応

TravisCIはGithubにあるリポジトリしかビルド対象にできません。Githubのサービスなんだから、当たり前といえば当たり前ですが・・・

(今のところ)無料

2014/1/23現在はベータのようです。将来的にはどうなるのかわからないですが、今のところ無料で使えます。制限としては「1つのビルドが25分以内に完了すること」ぐらいです。エンタープライズなシステムだとキツイかもですが、そこそこの規模なら問題ないんじゃないでしょうか。

テストを実行するための仮想環境が豊富に用意されている

werckerでビルドを実行する際にはBoxという仮想環境内で実行されます。これが予め様々な種類が用意されています。通常のRuby(Rails)の環境とかだけではなく、JavaやAndroidといった環境も用意されています。またBoxを自分で作ることもできるようです。

privateリポジトリもビルドできる

TracisCIは無課金だとprivateリポジトリはビルドできません。しかしwerckerはprivateリポジトリをビルドできます。 Photo LeafのソースはBitbucket上のprivateリポジトリで管理しているため、今までCIサービスを利用することができなかったのですが、werckerはprivateリポジトリでもビルドできるので便利です。

wercker.ymlの設定

Photo Leafでは、テストをrspecとcucumberで書いています。cucumberではjavascriptのドライバとしてcapybara-webkitを使ってます。そのためwerckerで動かすには設定が若干面倒です。

werckerにログインして、とりあえず普通にビルドするまでの手順は、以下の記事に詳しいのでこちらを参照してください。

上記で設定したwercker.ymlに対して、rspecとcucumberを実行するように設定していきます。自分が設定したwercker.ymlは以下のような感じ

wercker.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
box: wercker/rvm
# Build definition
# See the Rails section on the wercker devcenter:
# http://devcenter.wercker.com/articles/languages/ruby/settingup-rails4.html
# You will want to define your database as follows:
services:
    - wercker/postgresql
# See more about services on our devcenter:
# http://devcenter.wercker.com/articles/services/

build:
    steps:
        # Uncomment this to force RVM to use a specific Ruby version
        # - rvm-use:
        #       version: 2.1.0
        - script:
            name: Make tmp directory
            code: mkdir tmp

        - script:
            name: Enable virtual display
            code: |-
              # Start xvfb which gives the context an virtual display
              # which is required for tests that require an GUI
              export DISPLAY=:99.0
              start-stop-daemon --start --quiet --pidfile /tmp/xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset

              # Give xvfb time to start. 3 seconds is the default for all xvfb-run commands.
              sleep 3
        # Install (apt-get) packages
        - install-packages:
            packages: libqtwebkit-dev
        # A step that executes `bundle install` command
        - bundle-install

        # A step that prepares the database.yml using the database in services
        - rails-database-yml:
            service: postgresql

        # A custom script step, name value is used in the UI
        # and the code value contains the command that get executed
        - script:
            name: echo ruby information
            code: |
                echo "ruby version $(ruby --version) running"
                echo "from location $(which ruby)"
                echo -p "gem list: $(gem list)"

        - script:
            name: Set up db
            code: RAILS_ENV=test bundle exec rake db:schema:load

        - script:
            name: Run RSpec
            code: bundle exec rspec spec

        - script:
            name: Run Cucumber
            code: bundle exec cucumber features
  • 16~18行目 - テスト用のtmpディレクトリを作成(rspecのテストでtmpを使ってるので、必要なければ不要です)
  • 6~7,37~38行目 - テスト用のPostgreSQLを実行する
  • 53~55行目 - rspecを実行
  • 57~59行目 - cucumberを実行

capybara-webkitを動かすための注意点

capybara-webkitを動かすにはX11が使用できる必要があります。なのでXvfbを仮想環境で実行する必要があります。その設定が以下の部分。

wercker.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
- script:
    name: Enable virtual display
    code: |-
      # Start xvfb which gives the context an virtual display
      # which is required for tests that require an GUI
      export DISPLAY=:99.0
      start-stop-daemon --start --quiet --pidfile /tmp/xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset

      # Give xvfb time to start. 3 seconds is the default for all xvfb-run commands.
      sleep 3
# Install (apt-get) packages
- install-packages:
    packages: libqtwebkit-dev

上記の設定で仮想環境上でXvfbを実行できます。

まとめ

  • werckerはGithubとBitbucket両方に対応してるよ!
  • werckerは無料でprivateリポジトリもビルドできるよ!
  • capyabara-webkitを使うときにはXvfbを実行してよ!