grimrose's tech log http://grimrose.bitbucket.org/blog/html/ コードとか技術的な事を残しておきます en-us Mon, 11 May 2015 00:00:00 +0900 http://grimrose.bitbucket.org/blog/html/2015/05/11/openshift_hubot.html http://grimrose.bitbucket.org/blog/html/2015/05/11/openshift_hubot.html <![CDATA[既存のHubotアプリケーションをOpenShiftで動かすまで]]> 既存のHubotアプリケーションをOpenShiftで動かすまで

はじめに

HerokuでHubotを動かしていましたが、新しい料金プランの通知が来たので、他のクラウドサービスでも動かせるように出来ないかと思い、OpenShiftでやってみることにしました。

ただ、OpenShiftもDockerとKubernetesに対応したものに変わるということもあるので、それまでの経過措置です。

小さいインスタンスを24時間起動してても無料なサービスというのは、やはり儲からないのでしょうね。

参考にしたのは、Hitchhiker’s Guide to Tweetbots: Hosting a Hubot on OpenShift です。

OpenShiftへの登録

以下のサイトに登録の方法があるので、参考にしてください。

一旦、webの画面でサンプルアプリケーションとかを作って動かしておくと、今後の操作とかで省略出来る箇所もあるので、試しておくのをお勧めします。

rhcのインストール

登録が済んだら、コマンドラインツールが提供されているので、インストールします。

次にアカウントの情報を登録します。

公開鍵とドメインの設定をする必要がありますが、こちらもWebの画面でやっておくことをお勧めします。

Hubotアプリケーションの修正

参考にするのは、こちらです。

修正とは言っても、以下の2点です。

  • プロジェクトに .openshift/markers/use_npm という空のファイルを作る。
  • package.jsonに以下のようなHubot起動用のコマンドを追加する。
"scripts": {
"start": "PORT=$OPENSHIFT_NODEJS_PORT BIND_ADDRESS=$OPENSHIFT_NODEJS_IP HEROKU_URL=$OPENSHIFT_APP_DNS REDIS_URL=redis://:$REDIS_PASSWORD@$OPENSHIFT_REDIS_HOST:$OPENSHIFT_REDIS_PORT bin/hubot -n Hubot -a shell"
}

以下の3つの変数については、OpenShiftから提供されます。

  • OPENSHIFT_NODEJS_PORT
  • OPENSHIFT_NODEJS_IP
  • OPENSHIFT_APP_DNS

詳細は、Informational Environment Variables を参考にしてください。

redisに関しては、上記のサイトで利用しているcartridgeを使う場合と、https://marketplace.openshift.com/home で提供されているredis cloudを使う場合があります。

私の場合、redis cloudを使う選択をしたので、設定する必要があります。 アプリケーションに変数を設定するには先程インストールしたコマンドラインツールを利用します。

$ rhc env set OPENSHIFT_REDIS_HOST=<redisホスト名>
$ rhc env set OPENSHIFT_REDIS_PORT=<ポート>
$ rhc env set REDIS_PASSWORD=<パスワード>

hubot brainを使っていなかったので、データを移行する必要がありませんでした。 必要であれば、上記のサイトを参考に移行してください。

Hubotとslackと連携している場合は、以下の様に変数を設定してください。

$ rhc env set HUBOT_SLACK_TOKEN=<トークン>

Travis CIでデプロイ

OpenShiftはtravis CIでデプロイ出来るので、以下の様に設定します。

language: node_js
node_js:
  - "0.10"
deploy:
  provider: openshift
  user: $OPENSHIFT_USERNAME
  password: $OPENSHIFT_PASSWORD
  app: $OPENSHIFT_APP_NAME
  domain: $OPENSHIFT_APP_NAMESPACE

ユーザ名とパスワードをtravisに設定するところが気になるところですが、OpenShiftにデプロイ用のトークン機能が無いので仕方ありません。

設定方法は、Using Settings を参考にしてください。

上記の OPENSHIFT_APP_NAMESPACE ですが、ドメイン名を設定します。

最後に

単純な移行だけなら、上記の設定をしてgit pushのremoteを変更するだけでなんとかなります。

もしHubotでスケジューリングしている様な場合は、単純に移行してしまうとタイムゾーンの関係でズレてしまうと思います。

私自身、OpenShift上のNode.jsアプリケーションでタイムゾーンを変更する方法が分からないので、変更する方法を知っている方がいらっしゃったら、教えて頂けると助かります。

本格的にHeroku上でHubotを使っている場合、素直にHobbyプランまたはそれ以上に移行するのがいいと思います。

追記 2015-05-11

OpenShiftも48時間でアイドリングするので、@bouzuya さんの解決策を採用させていただくことにしました。

追記 2015-05-17

OpenShiftでのタイムゾーンの変更ですが、@nekop さんに教えて頂きました。ありがとうございます。

プロジェクトに .openshift/action_hooks/pre_start_nodejs を作ります。

内容は、以下の通りで変えることが出来ました。

#!/bin/bash

echo "Execute pre_restart nodejs hook"

export TZ='Asia/Tokyo'

echo "$TZ"
echo `date`
]]>
Mon, 11 May 2015 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2015/01/24/tinkerer_with_open_graph_protocol.html http://grimrose.bitbucket.org/blog/html/2015/01/24/tinkerer_with_open_graph_protocol.html <![CDATA[TinkererでOpen Graph Protocol(OGP)を使う]]> TinkererでOpen Graph Protocol(OGP)を使う

はじめに

Open Graph Protocol(OGP)

これだけは知っておきたいOGP (Open Graph Protocol)

http://nex.fm/ogp/

前から気になっていたのですが、このブログで使っている Tinkerer でのやり方が分からなかったので、放置してましたが、対応していた方がいらっしゃったので、試してみました。

このブログにOGPを設定した

http://misc.mat2uken.net/blog/2013/05/31/setting_ogp.html

やりかた

こちらを参考にしながらやってみました。

Tinkererでは、layout.htmlを作ることで、全体に対応した既存のテンプレートを拡張出来るみたいです。

_templatesディレクトリを作る

プロジェクト直下に _templates ディレクトリを作成します。

私の場合、既にはてブボタンや、twitterのボタンを追加する為に作っていました。

_templates/layout.htmlを作る

layout.htmlは作っていなかったので、以下のコードを記載して追加しました。

{% extends "!layout.html" %}

{% block extrahead %}

<meta property="og:title" content="{{ shorttitle }}" />
<meta property="og:description" content="{{ title|striptags|e }}" />
<meta property="og:url" content="http://grimrose.bitbucket.org/blog/html/{{ pagename }}{{ file_suffix }}" />
<meta property="og:image" content="http://grimrose.bitbucket.org/blog/html/_static/ogp_image_400x400.jpeg" />

{% endblock %}

index.htmlにも追加する

プロジェクト直下のindex.htmlにも設定しておくと、いいと思います。

今回は、以下のタグを追加しました。

<meta property="og:title" content="grimrose's tech log" />
<meta property="og:description" content="ホーム" />
<meta property="og:url" content="http://grimrose.bitbucket.org/" />
<meta property="og:image" content="http://grimrose.bitbucket.org/blog/html/_static/ogp_image_400x400.jpeg" />

Open Graph Object Debuggerで確認する

後は、buildして、pushして、確認します。

Open Graph Object Debugger

https://developers.facebook.com/tools/debug/og/object/

自分のブログの記事のURLを入れてください。

When shared, this is what will be included の箇所に表示されます。

間違いがあったりすると、いろいろ指摘されます。

まとめ

Tinkererは、あれこれやりたいなと思った時に拡張するためのポイントが最小限になっているのが、ありがたいですね。

]]>
Sat, 24 Jan 2015 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/12/31/g_advent_calendar_2014_ratpack_overtime.html http://grimrose.bitbucket.org/blog/html/2014/12/31/g_advent_calendar_2014_ratpack_overtime.html <![CDATA[Ratpackについて(延長戦)]]> Ratpackについて(延長戦)

はじめに

G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014Ratpack についての紹介をしました。

テスティングフレームワークや、CircleCI、Heroku buttonについての紹介もしてみたいと思います。

Ratpackのテスティングフレームワーク

http://www.ratpack.io/manual/current/testing.html

http://www.ratpack.io/manual/current/groovy.html#testing

Ratpackには、UnitTest, GroovyUnitTest, ApplicationUnderTest のようにテスト用のヘルパークラスが用意されています。

使い方は、TestHttpClient を参考にしてください。

テストヘルパーを組み合わせる事で、定型的なセットアップも簡単に記述することが出来ます。

また、Geb と組み合わることで簡単に Selenium WebDriver を使ったテストを書くことが出来ます。

RemoteControlModule を使うと Groovy Remote Control を呼ぶことが出来るので、テストに必要なデータなどを予め登録することが出来ます。

CircleCI

https://circleci.com/

最近では、CIのサービスが増えており、Travis CI 以外の選択肢も選べるようになってきました。

Ratpack本体は、ビルドパイプラインが特徴的な Snap CI を利用しているみたいです。

publicなレポジトリでも利用できるようになったCircleCIが注目されているので、Ratpackで使える設定をしてみます。

その他のGradleを使ったWebアプリケーションのプロジェクトにも応用できると思います。

まず、GitHubのレポジトリの SettingsWebhooks & Services を選びます。

次に、Add Service から CircleCI を追加します。

circle.ymlが無くてもCircleCI側でいろいろ空気を読んでくれますが、Ratpackでは、Java8とGradle2.xを使う関係上、circle.ymlを追加する必要があります。

circle.ymlの書き方は、 Sample circle.yml file を参考にしてください。

以下の様にすると、postgresqlでのテスト、Herokuへのdeployが出来るようになります。

Herokuへdeployする為には、予めCircleCIの Project Settings から Continuous Deployment のHerokuにてデプロイする為の設定を行う必要があります。

machine:
  java:
    version: oraclejdk8
  timezone:
    Asia/Tokyo
  environment:
    DATABASE_URL: postgres://ubuntu:@127.0.0.1:5432/circle_test

dependencies:
  override:
    - ./gradlew dependencies

  cache_directories:
    - "~/.gradle"

test:
  override:
    - ./gradlew test

deployment:
  staging:
    branch: master
      heroku:
      appname: foo-bar-123

Heroku buttonについて

Creating a ‘Deploy to Heroku’ Button

Herokuには、自分のレポジトリのコードを他の人がHeroku上で利用できるようにする Heroku Button を提供する機能があります。

折角なので、今回のサンプルプロジェクトを対応させてみます。

手順は、以下の通りです。

  • app.json ファイルをプロジェクトの直下に設置する。
  • READMEにボタンを設置する。

app.jsonの内容については、app.json Schema を参考にしてください。

とはいえ、人の手で書いていくには少し骨が折れる作業なので、app.json を利用して作ってしまいましょう。

app.jsonを使うにはnode.jsをインストールしておく必要があります。

あと、herokuのgitの設定によっては失敗するかもしれません。 その際は、.git/config のherokuのurlを確認してください。必要に応じて修正する必要があります。

READMEには、以下の様にするとボタンを設置する事が出来ます。

ボタンは、こんな感じです。

Deploy

まとめ

以前に比べてアプリケーションを動かす環境やCIと連携できるサービスが簡単になってきました。

Gradleやモダンなフレームワークを利用することで、JavaやGroovyでもアプリケーションサーバを用意せずに使えたり、組み込みにすることでポータビリティを上げられています。

Ratpack以外にも、JavaやGroovyのWebアプリケーションをHerokuへのデプロイやCIサービスとの連携が出来ると思いますので、試してみてはいかがでしょうか。

]]>
Wed, 31 Dec 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/12/07/g_advent_calendar_2014_ratpack_02.html http://grimrose.bitbucket.org/blog/html/2014/12/07/g_advent_calendar_2014_ratpack_02.html <![CDATA[Ratpackについて(後編)]]> Ratpackについて(後編)

はじめに

この記事は、G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014 の7日目として書かれたものです。

6日目は @grimrose さんの Ratpackについて(前編) です。

8日目は、@nobusue さんの Gradle Groovy Shellプラグインを使って依存ライブラリ込みのREPLを起動する #gadvent です。

Ratpackプロジェクトの作り方

Ratpackは、lazybones を使うと簡単にプロジェクトを作る事が出来ます。

lazybonesは GVM からインストールすることが出来ます。

$ gvm install lazybones

lazybonesからRatpackのプロジェクトを作る場合、無印とliteが選べますが、今回はmoduleを作りますので無印で行います。

liteの方は、クラスやテストのディレクトリが無いシンプルな構造をしています。目的にあわせてプロジェクトを作る事が出来ますので、Hello Worldを試したい場合は、liteで作ってみてはいかがでしょうか。

以下のコマンドを実行すると、その場所にプロジェクトが出来ます。

$ mkdir sample
$ cd sample
$ lazybones create ratpack .

lasybonesには、プロジェクト作成時のオプションがあるので、lazybones create だけ実行して確認してください。

IntelliJ IDEAかEclipseで取り込む前に、GradleでIDEのプロジェクトファイルを作っておきましょう。

$ gradle idea
## or
$ gradle eclipse

springloadedについて

2014年12月現在、標準でspringloadedが適用されていますが、http://forum.ratpack.io/springloaded-error-td681.html を見る限り、うまく動作しない模様なので、コメントアウトしておくのをおすすめします。

ディレクトリ構成について

Ratpackは以下の様なディレクトリの構成を取ります。

特徴的なのはratpackディレクトリです。このディレクトリの中に静的なファイルやratpack.groovyを置きます。

<proj>
  |
  +- src
      |
      +- ratpack
      |     |
      |     +- ratpack.groovy
      |     +- ratpack.properties
      |     +- public          // 静的なファイル等のassets
      |          |
      |          +- images
      |          +- lib
      |          +- scripts
      |          +- styles
      |
      +- main
      |   |
      |   +- groovy
              |
              +- // アプリケーションのクラス
      |
      +- test
          |
          +- groovy
              |
              +- // Spock のテスト

起動と停止

起動する場合は、以下のコマンドで出来ます。

$ gradle run

起動すると、デフォルトでは localhost:5050 で待ち受けているので、ブラウザでアクセスしましょう。

停止は、Ctrl + Cで出来ます。

お題

今回は、メッセージの登録と表示のWebアプリケーションを作ってみます。

View

lazybonesで作ったプロジェクトのテンプレートエンジンは、GroovyTemplateなのでそのまま使います。

GroovyTemplateは、拡張子が任意なので、HTMLをそのままテンプレートとして扱う事が出来ます。

また、The MarkupTemplateEngine を使うとGroovyを使ってより柔軟にレイアウトを記載できます。

今回は、一つのページで登録と一覧を行い、一覧は、JSON APIを呼んで表示するようにしてみたいと思います。

ルーティング(Routes)

ratpack.groovy のルーティングに関する箇所、以下の通りです。

handlers {
  get {
    render groovyTemplate("index.html", title: "Message App")
  }

  handler('messages') {
    byMethod {
      get {
        redirect '/' // index.htmlへリダイレクト
      }
      post {
        // メッセージを登録する。
      }
    }
  }

  delete('messages/:id') {
    // メッセージを削除する。
  }

  handler('api') {
    // メッセージの一覧をJSONで返す。
  }

  assets "public"
}

Moduleについて

今回用意するモジュールは、以下の通りです。

  • SQL
  • HikariCP
  • RxJava
  • Jackson
  • テンプレート
  • 今回作成するメッセージに関するモジュール

それぞれを bindings ブロックにて登録します。

bindings {
  add TemplatingModule

  add(HikariModule) { HikariConfig config ->
    config.driverClassName = 'org.postgresql.Driver'

    // Herokuとローカルをここで切り替える
    def uri = new URI(System.env.DATABASE_URL ?: "postgres://test:test@localhost/gadvent2014")

    def url = "jdbc:postgresql://${uri.host}${uri.path}"
    username = uri.userInfo.split(":")[0]
    password = uri.userInfo.split(":")[1]

    config.jdbcUrl = url
    config.username = username
    config.password = password
  }
  add new SqlModule()
  add new JacksonModule()

  // 今回作成するメッセージに関するモジュール
  add new MessageModule()

  init { MessageService messageService ->
    RxRatpack.initialize()
    messageService.init()
  }
}

アプリケーション

今回作成したのは以下のクラスです。

import groovy.transform.Canonical

@Canonical
class Message {
  Long id
  Date createAt
  String contents
}

import com.google.inject.AbstractModule
import com.google.inject.Scopes

class MessageModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(MessageRepository).in(Scopes.SINGLETON)
    bind(MessageService).in(Scopes.SINGLETON)
  }

}

import com.google.inject.Inject
import groovy.sql.Sql
import groovy.util.logging.Slf4j
import rx.Observable

import java.sql.Timestamp

@Slf4j
class MessageRepository {

  @Inject
  private Sql sql

  void initialize() {
    log.info "Creating tables"
    sql.executeUpdate("DROP TABLE IF EXISTS messages")
    sql.executeUpdate("CREATE TABLE IF NOT EXISTS messages (id SERIAL PRIMARY KEY, createAt TIMESTAMP, contents TEXT)")
  }

  Observable<List<Message>> findAll() {
    Observable.from(sql.rows("SELECT id, createAt, contents FROM messages ORDER BY createAt")).map {
    new Message(id: it.id, createAt: it.createAt, contents: it.contents)
    }.toList()
  }

  def insert(Message message) {
    sql.executeInsert("INSERT INTO messages (createAt, contents) VALUES (?, ?)", new Timestamp(message.createAt.getTime()), message.contents)
  }

  def delete(long id) {
    sql.executeUpdate("DELETE FROM messages WHERE id = ?", id)
  }

}

import com.google.inject.Inject
import groovy.util.logging.Slf4j

@Slf4j
class MessageService {

  @Inject
  MessageRepository repository

  void init() {
    repository.initialize()
  }

  def all() {
    repository.findAll()
  }

  def create(String contents) {
    Message message = new Message(createAt: new Date(), contents: contents)
    repository.insert(message)
  }

  def delete(long id) {
    repository.delete(id)
  }

}

これらのクラスを ratpack.groovy から利用します。

handlers { MessageService messageService ->
  get {
    render groovyTemplate("index.html",
      title: "Message App"
    )
  }

  handler('messages') {
    byMethod {
      get {
        redirect '/'
      }
      post {
        // メッセージを登録する。
        Form form = parse(Form)
        def contents = form.get('contents', '')
        if (!contents) {
          render groovyTemplate('index.html',
            title: "Message App",
            errorMessage: 'メッセージを入力してください'
          )
        } else {
          context.blocking {
            messageService.create(contents)
          }.then {
            redirect '/'
          }
        }
      }
    }
  }

  delete('messages/:id') {
    // メッセージを削除する。
    def id = pathTokens["id"].toLong()
    context.blocking {
      messageService.delete(id)
    }.then {
      render Jackson.json('success')
    }
  }

  handler('api') {
    // メッセージの一覧をJSONで返す。
    messageService.all().subscribe { List<Message> messages ->
      render Jackson.json(messages)
    }
  }

  assets "public"
}

今回作成したアプリケーションのソースは、こちらに公開しています。

https://github.com/grimrose/gadvent2014

herokuへのデプロイ

あらかじめHerokuのアカウントを登録しておきます。

以下のコマンドでログイン出来る事を確認してください。

$ heroku login

RatpackはJava8のJVMで動かす必要があるので、system.properties には、以下の様に記載します。

java.runtime.version=1.8

Ratpackのプロジェクト名によってHerokuでの設定値が利用されるので、プロジェクト名を setting.gradle に指定します。

rootProject.name = "«project name»"

Ratpackはアプリケーションのポートを 5050 をデフォルトとして利用しますが、Herokuは指定されたポートで動かす必要がありますので、Prockfile には以下の様に記載します。

また、アプリケーション固有の設定をプロジェクト名を大文字にした «PROJECT_NAME»_OPTS として設定することが出来ます。 例えば、g-advent-2014 といったプロジェクト名であれば、G_ADVENT_2014 といった様に定義されます。

web: env "«PROJECT_NAME»_OPTS=-Dratpack.port=$PORT" build/install/«project name»/bin/«project name»

ここで作成した、system.properties, setting.gradle, Procfile をコミットしたら、準備完了です。

JavaのWebアプリケーションをHerokuで動かすには、buildpack が必要になります。

Ratpackは特殊なbuildpackではなく、Gradleのbuildpackを使用します。

以下のコマンドで、Herokuに新規アプリケーションを作成します。

$ heroku create --buildpack https://github.com/heroku/heroku-buildpack-gradle

今回のアプリケーションでは、RDBMSとしてPostgreSQLを使いますので、Herokuのアドオンを追加します。

$ heroku addons:add heroku-postgresql

以下のコマンドを実行して、Herokuにpushしましょう。

$ git push heroku master

最後に、以下のコマンドで始めることが出来ます。

$ heroku open

まとめ

Ratpackは、小さなWebアプリケーションを作るのに向いているので、モジュールを組み合わせて大きくしていくのに向いてます。 また、NettyをベースにしているためWebSocketアプリケーションが作れます。

但し、いいところばかりでは無く、日本語の情報やドキュメントも不十分な箇所もあります。

また、非同期処理について知識が無いと、テストやデバッグでハマってしまったり、ブロックしてしまうコードを書いてパフォーマンスが出ないといったこともありえます。

既存のServletベースのアプリケーションでは物足りなかったり、他のNettyベースのフレームワークとは一味違った開発をしてみたいチャレンジャーな人は、試してみてはいかがでしょうか。

]]>
Sun, 07 Dec 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/12/06/g_advent_calendar_2014_ratpack_01.html http://grimrose.bitbucket.org/blog/html/2014/12/06/g_advent_calendar_2014_ratpack_01.html <![CDATA[Ratpackについて(前編)]]> Ratpackについて(前編)

はじめに

この記事は、G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014 の6日目として書かれたものです。

5日目は @kyon_mm さんの Geb 0.10の新機能紹介 #gadvent です。

7日目は @grimrose さんの Ratpackについて(後編) です。

Ratpackとは

http://www.ratpack.io/

Ratpackは、NettyをベースとしたJava8とGroovyで書かれたWebアプリケーションフレームワークです。

アプリケーションもまた、Java8またはGroovyで記述出来ます。

フルスタックなフレームワークではなく所謂、MicroWebフレームワークとか軽量Webフレームワークとか呼ばれるカテゴリに属しています。

一番の特徴としては、Nettyをベースにしていることもあるので、Asynchronous & Non Blocking です。

JavaでWebアプリケーションフレームワークというと、ServletやFilterをラップしたフレームワークが多いですが、その場合、別途GlassfishやTomcat, Jettyといったアプリケーションサーバが必要です。

もちろん組み込み可能なアプリケーションサーバを内蔵してwarファイルから起動というようなことも出来ます。

そういった従来のServlet前提のWebアプリケーションとは違い、Ratpackはアプリケーションサーバを必要としません。

fat-jarやZipで固めてデプロイ出来るフレームワークなので、Dockerなどのコンテナと相性が抜群です。

他のWAFとの違い

http://www.ratpack.io/manual/current/intro.html#compared_to

Ratpackから見た他のWebアプリケーションフレームワークとの違いは、以下のような内容です。

Netty

http://netty.io

Nettyは、Ratpackのベースとなっているように、低位のレイヤーをサポートしてるライブラリです。 HTTP以外のプロトコルもサポートしているため、NettyをベースにしたフレームワークはRatpack以外にも様々存在します。

RatpackはNettyをベースとしていますが、オーバーヘッドになるような処理は加えておらず、パフォーマンスはNettyと遜色ありません。

パフォーマンスを優先したいような場合は、NettyのAPIにアクセス出来るようになっています。

Vert.x

http://vertx.io

Vert.xは、個人的に好きなフレームワークで、Ratpackと同じくNettyをベースとしています。

各モジュールがJSONをメッセージバスを介してやりとりを行うようなアプリケーションコンテナとしての性格が強く、言語もJavaやGroovy以外のJVM上で動作できるものを組み合わせて扱うことが出来るようになっています。

また、非同期の処理を行う手段として、コールバックを採用しました。

Ratpackは、よりHTTPに特化しており、Vert.xのWebアプリケーションフレームワークである Yoke に似てます。また、非同期処理の手段は、Vert.xと違い、所謂 Promise を基調とした処理を採用しています。

RxNetty

https://github.com/Netflix/RxNetty

RxNettyは、RxJavaを使い、NettyのAPIをよりリアクティブにしたものです。

Grails

http://grails.org

言わずと知れたGroovyのフルスタックなWebアプリケーションフレームワークです。

Servletをベースとし、SpringFramework, Groovyを採用したフレームワークで、様々なプラグインを組み合わせることで多機能なアプリケーションを作ることが出来ます。

Spark

http://www.sparkjava.com

並列データ処理フレームワークである Apache Spark ではなく、Sinatraに影響を受けたMicroWebフレームワークです。

Servletをベースとしていますが、Servlet APIを意識させないようなコードを書かせるようなフレームワークです。

また、Java8のlambda式を使うことで、より短く簡潔に書けるようになっています。

組み込みアプリケーションサーバのJettyを採用しているので、fat-jarでデプロイすることが出来ます。

Dropwizard

https://dropwizard.github.io/dropwizard

RatpackのページではTBD扱いされていますが、2014年注目されたWebアプリケーションフレームワークの一つです。

Javaでは定番のライブラリを採用したフルスタックなフレームワークです。

組み込みアプリケーションサーバを内蔵し、fat-jarでデプロイ可能というコンセプトは、Twelve-Factor App に基いており、Immutable Infrastructureと相性が良く、そのアイデアの素晴らしさからか、Springframeworkへかなり影響を与え、SpringBootがリリースされたのは記憶に新しいところです。

アーキテクチャ

Ratpackは, MVC2で言われる所謂コントローラー層としての機能を担当しています。

ratpack.handling.Context とそれを扱う ratpack.handling.Handler が主なInterfaceです。

Handlerは所謂FunctionalInterfaceなので、lambda式で書くことが出来ます。

ビュー層は、以下のテンプレートエンジンであれば、モジュールが用意されています。

  • handlebars
  • thymeleaf
  • Groovy Template

APIとして使う場合にも、JacksonやGroovyのJSONのモジュールが用意されています。

モデル層は、特定のものが用意されている訳ではありませんが、Ratpackが用意しているモジュールにはH2、HikariCPといったものがあるので利用できます。 もちろんGroovyが使えるので、GroovyのSQLに関する機能も使えます。

DIコンテナとしてGuiceが用意されているので、モジュールを作ればモデル層や他のテンプレートエンジン等を使うことが出来ます。

モデル層で注意しなければならないのは、Nettyがイベント駆動のエンジンであることから、イベントループをblockする コード、例えばDBにアクセスするコード等です。

但し、Ratpackでは、blockするような場合は、明示的に Context#blocking(Callable) を使うことで対応できます。

また、Context#promise(Action<Fulfiller<T>>) を使うことで、同期的な処理をすることが出来ます。

HTTPのリクエストやレスポンスは、Contextから取得する事で利用できます。

こういったHandlerの処理を src/ratpack/ratpack.groovy に記載していきます。

Groovyの場合は、以下のように記載していきます。

import static ratpack.groovy.Groovy.ratpack

ratpack {
  handlers {
    get {
      render "Hello world!"
    }

    get('foo')  {
      render "Foooooooo!"
    }

  }
}

後編へつづく

次回は、実際にRatpackを使ったWebアプリケーションを作ってHerokuへ公開するまでを紹介してみたいと思います。

]]>
Sat, 06 Dec 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/10/31/rxjava_night_2014.html http://grimrose.bitbucket.org/blog/html/2014/10/31/rxjava_night_2014.html <![CDATA[RxJava Night でVert.xについて話してきました #rxjnight]]> RxJava Night でVert.xについて話してきました #rxjnight

RxJava Night #rxjnight

http://connpass.com/event/9061/

はじめに

RxJavaは、あまり使ったことは無いのですが、Vert.xに mod-rxvertx があったり、 @muraken720 さんの RxJavaを使ってCallback Hellから脱出する( Vert.x がいいね!第5回 ) の記事を見て興味があったので、3.0に向けていろいろと動き出している事と、気になっていた Reactive Streams と併せて話してみたいと思ってたので、参加しました。

資料

Vert.xからみたReactive Streams

http://www.grimrose.org/RxJavaNight2014/

MDwiki

Markdownをスライド代わりに使うことがあったのですが、もう少し凝ったことをしてみたいと思ってたので、MDwiki を使ってみました。

他の方のスライドを紹介したかったので、iframeを埋め込んだり出来たのは良かったです。

本来であればWikiに使うのが正しいと思いますが、MDwiki example websites を見る限りいろいろと応用が出来そうです。

感想

参加者の多くは、Androidを使ってる人のようでした。 ReactiveX/RxAndroid の話もありましたし、AndroidでCallbackを書くのはつらそうなので、そういった意味でも注目されていたようです。

サーバーサイドの方が少なかったのは、RxJavaを実際に使ってる人が少ない上に、あえて使うような状況に遭遇しにくいからではないかと思いました。 Java8と組み合わせることでかなりすっきりと書けるので、Java8という選択肢がない現場では興味の対象となりにくいのかもしれないと感じました。

とはいえ、Netflix の様にJavaまたはJVMで動作する言語でサーバーサイドを書いていますし、Rx本家のC#もゲームサービスのバックエンドに使われているので、今後はそういったお話が出てくるが楽しみです。

今回は、Rxの歴史を知ることが出来たのが一番興味深かったです。

懇親会では、Rxの考え方とかテストはどうしたらいいのか等をお伺いすることが出来たので試してみたいと思います。

Vert.xについては、3.0に向けていろいろ情報収集をしつつ、触っていければと思います。

主催者の @hotchemi さん、発表者の皆さん、会場を提供して下さったPixivさん、ありがとうございました。

]]>
Fri, 31 Oct 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/10/20/template_engine_night_2014.html http://grimrose.bitbucket.org/blog/html/2014/10/20/template_engine_night_2014.html <![CDATA[テンプレートエンジンNightでGroovy Templateの紹介をしてきました #tenight]]> テンプレートエンジンNightでGroovy Templateの紹介をしてきました #tenight

はじめに

テンプレートエンジンNight

http://www.zusaar.com/event/10707003

Groovyには、テンプレートエンジンが標準で仕様に入っているので、紹介してきました。

補足

  • Simple Template Engineは、以下のように使います。

    import groovy.text.SimpleTemplateEngine
    
    def text = 'Hello "$placeHolder"!'
    def binding = ["placeHolder":"Groovy"]
    
    def engine = new SimpleTemplateEngine()
    template = engine.createTemplate(text).make(binding)
    
    assert 'Hello "Groovy"!' == template.toString()
    
  • Simple Template Engineの詳細な使い方はこちらです。

    G*Magazine Vol.6 オレオレ・プログラミング GROOVY

    http://beta.mybetabook.com/showpage/51053be10cf2ffb79bb047f0

  • GroovyのテンプレートエンジンはJavaからでも利用することが出来ます。

    例えば、Markup Template Engineを使う場合は、以下のとおりです。

    try (StringWriter writer = new StringWriter()) {
        TemplateConfiguration config = new TemplateConfiguration();
        MarkupTemplateEngine engine = new MarkupTemplateEngine(config);
        // createTemplateにはStringの他にReader, URLを渡せます
        Template template = engine.createTemplate("p('test template')");
        Map<String, Object> model = new HashMap<>();
        Writable output = template.make(model);
        // java.io.Writerを継承したインスタンスを渡してください
        output.writeTo(writer);
        System.out.println(writer);
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
    
  • Groovyのテンプレートエンジンの機能についての詳細は、こちらです。

    Template engines

    http://groovy-lang.org/templating.html

  • JsonBuilderは、以下の様にClosureを使って書くことが出来ます。

    import groovy.json.*
    
    def json = new JsonBuilder()
    json {
        message {
            text "Hello Groovy!"
        }
    }
    println json
    // 整形して出力することも出来ます
    println json.toPrettyString()
    
    {"message":{"text":"Hello Groovy!"}}
    {
        "message": {
            "text": "Hello Groovy!"
        }
    }
    

    JsonBuilderのサンプルはこちらです。

    http://groovyconsole.appspot.com/script/498001

    GroovyにはJSONのParserもあります。

    http://groovy-lang.org/json.html

  • スライドで紹介したGroovy Template を利用しているプロダクトはこちらです。

Groovyには、テンプレートエンジン以外にもJavaから使える機能が沢山あります。

また、Gradle は2.0からであればGroovy2.3の機能を使えるので、試してみてはいかがでしょうか。

感想

JVM以外のテンプレートエンジンのお話も聞けて、当日はとても楽しかったです。

当日は、JavaというかJVMのエンジニアが少なく、PHP, Perl, Rubyの方が多い印象でした。

Webデザイナーさんとの協業を考えると、HTMLのDOMにどうアプローチするのかを考えないと、お互いの為にならないということを知りました。

その他にも、JVM以外のテンプレートエンジンでの苦労話を聞いて、かなり勉強になりました。

Groovyを知ってたり使ってらっしゃる方が多かったのは、個人的には意外でした。

やはり、AndroidでGradleが採用されたから使っているというのが大きいのではないかと思います。

あと、Pixivさんのオフィスに初めてお邪魔して、楽しそうだなぁと思いました。

Smarty2で苦労されていらっしゃるみたいですが、良い解決策が見つかる事を願ってます。

主催者の @moznion さん、発表者の皆さん、会場を提供して下さったPixivさん、ありがとうございました。

また別のNightでお会いしましょう。

]]>
Mon, 20 Oct 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/07/22/submit_your_gradle_plugin.html http://grimrose.bitbucket.org/blog/html/2014/07/22/submit_your_gradle_plugin.html <![CDATA[Gradle plugin を公開してみよう]]> Gradle plugin を公開してみよう

Gradle plugin portal

http://plugins.gradle.org/

ついに、待望のGradleのPluginを管理するシステムが動き出し始めました。

これで、GradleのPluginを探しまわらなくても、公開しても自分しか使ってない寂しい思いをしなくても良くなります。

GradleのPluginの作り方は、 Chapter 58. Writing Custom Plugins第58章 カスタムプラグインの作成 を参考にしてください。

公開するための手順

注意: 2014-07-22現在の手順なので、変更されている場合があります。

http://plugins.gradle.org/submit

1. Gradle Plugin ID

以前から自分が使うために作っていたGradle Pluginを公開してみようと思いましたので、それをリリースしてみます。

対象は、 gradle obake plugin です。

If you have an existing plugin with ID foo and are GitHub user “bar”, a suitable new plugin ID would be com.github.bar.foo.

私の場合、bitbucketを公開repositoryとして使っていたので、org.bitbucket.grimrose.obake としました。

自分のドメインを持っている方であれば、org.example.plugin_id みたいになると思います。

gradle をIDに含めなる必要はないので、注意してください。

既に、Gradle Pluginを作っている場合は、既存のpropertiesを META-INF/gradle-plugins/${Gradle_plugin_ID}.properties へ変更してください。

新たに追加しても大丈夫みたいです。

2. Bintray へアップロード

bintray/gradle-bintray-plugin を使うことで、 簡単にアップロード出来るようになります。

bintray pluginについてはサンプルがあるので、bintray/bintray-examples を参考にしてください。

Bintrayのアカウントがない場合、GradleでBintrayにアップロードする手順 を参考にしてください。

3. JCenterへ登録

mavenのrepositoryへリリースしたjarは、JCenterで公開出来るようになります。

詳細は、Including Your Packages in JCenter を参考にしてください。

完了すると、以下の様なMessageが返ってくるので、それまで待ちましょう。

Your request to include your cool package /grimrose/maven/gradle-obake-plugin in Bintray’s JCenter has been approved.

4. Gradle Plugins repositoryへ登録

Gradle Plugins Bintray repo へ移動します。

Include My Package ボタンを押すと、未登録のパッケージが表示されるようになります。

そのまま申請すれば、完了です。

完了すると、以下の様なMessageが返ってくるので、それまで待ちましょう。

Your request to include the package /grimrose/maven/gradle-obake-plugin in the repo /gradle/gradle-plugins has been approved.

5. リリースするversionに’gradle-plugin’の属性を付与

もし、アップロードしたversionに gradle-plugin の属性がついてないと、Gradle Plugins repositoryへ登録されません。

手動で付ける場合は、公開するversionを選んで、中央あたりにある Edit を押します。

次に、Attributes List を選択し、Add New Attribute を押します。

表示された Name には、gradle-plugin を、Value には以下のような値を入力します。

«id»:«group»:«name»

今回の場合、org.bitbucket.grimrose.obake:org.bitbucket.grimrose:gradle-obake-plugin となります。

右の + ボタンを押すと入力した属性が追加されます。

最後に、Update ボタンを押すと完了です。

About This Version の項目に gradle-plugin の項目が追加されていれば、成功です。

bintray pluginであれば、bintray.pkg.version.attributes ブロックに定義しておくことで、アップロードの際に自動的に属性をつけてくれます。

6. リリース完了

全て成功したら、早速 Gradle plugin portal で検索してみましょう。

リリース直後であれば、一番上に自分のpluginが表示されていると思います。

おめでとうございます、これで完了です。

公開したGradle pluginの使い方

公開したGradle Pluginを利用する場合、build.gradle に以下のコードを追加します。

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath "org.bitbucket.grimrose:gradle-obake-plugin:0.6"
  }
}

apply plugin: "org.bitbucket.grimrose.obake"

2.1以降は、以下の様な書き方が出来る模様です。

plugins {
  id "org.bitbucket.grimrose.obake" version "0.6"
}

最後に

一度、承認されれば、以降リリースの度に自動的に反映されます。

元々Bintrayで成果物を管理していたお陰で、早く適用することが出来ました。

他の言語のビルドツールのようなPluginがどんどん増えると思うので、とても楽しみです。

Gradleも2.1で期待してる機能が追加されるみたいなので、期待して待ってます。

]]>
Tue, 22 Jul 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/06/21/jggug_jun_2014.html http://grimrose.bitbucket.org/blog/html/2014/06/21/jggug_jun_2014.html <![CDATA[Grainの紹介]]> Grainの紹介

わいわいGroovy ~ 教えてG*小ネタ大会 - JGGUG G*ワークショップZ Jun 2014Grain を紹介してきました。

併せて今回のスライドは、Grainを利用して作ってみました。

grimrose/jggug-jun-2014

公開先はこちら

http://grimrose.github.io/jggug-jun-2014

静的サイトを作るプロダクトは、JekyllOctopress などがありますが、Groovyで作られたのがGrainです。

今回は、Grain Theme Template を利用しましたが、Octopress Theme もあるので、Blogを書くことも出来ます。

また、GitHub Pagesで公開する場合には、コマンド2つだけで出来るので、簡単です。

時間が足りなくて、デモで出来なかったのは残念でした。

公開のタスクは、Grain Gradle Plugin の場合、以下のコマンドを実行するだけで出来ます。

まず、previewで確認して、完成したらHTMLを生成します。

$ gradle grainGenerate

そして、デプロイします。

$ gradle grainDeploy

プロジェクトのGitHub Pagesの場合 gh-pages branchを作る必要がありますが、これはGrainが自動的に作成してくれます。

その他にもいろいろと興味深い機能があるので、今後も使っていこうと思います。

]]>
Sat, 21 Jun 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/04/09/vert_x_de_scala.html http://grimrose.bitbucket.org/blog/html/2014/04/09/vert_x_de_scala.html <![CDATA[ScalaをVert.xで利用する]]> ScalaをVert.xで利用する

渋谷Java

第五.五回 #渋谷java

http://connpass.com/event/5482/

Vert.x de Scala

grimrose / shibuya-java-05-5

今回の発表に向けて、何か新しい事をしてみたいと思って色々と考えてました。 スライドをhtmlで作るのをやってみたいと思っていたので、今回はそれをテーマにしてみました。 挑戦する内容は、以下の項目を上げてみました。

  • Scala
  • Jade
  • reveal.js

その他、採用したものについて色々と補足してみたいと思います。

祝! lang-scala-1.0.0

vert-x / mod-lang-scala

ここ数日で一気にアップデートされました。次の2.1.0から標準で入るっぽいです。

[lang-scala] mod-lang-scala 1.0.0 is out!

Scalaで Netty ベースのフレームワークというと Finagle が有名ですが、Vert.xもScala Readyとなったことで非同期処理のノウハウが共有されていくといいと思います。

reveal.js

hakimel / reveal.js

htmlをスライドにするプロダクトは様々ありますが、組み合わせて使うならこれが最適だと思います。

特にPDFに出力出来る機能を備えているのは、ありがたいと思います。

ただ、PDFで出力するにはレイアウトを上手く扱う必要があるので、作りながら微調整するといいと思います (作った後からPDFで出力してみたら、残念な結果になってしまったので)。

Scalate

Scalate

reveal.jsに渡すhtmlを生成するのに、Scalaではどの形式なら可能か調べていたところ、テンプレートエンジンとしてScalateが見つかりました。

Scalateは、今回採用したJade以外にMustache、Scaml、SSP、Scueryが利用できます。

Jadeの中でScalaの構文が使えたり、色々と出来るのが面白いと思います。

vertx-gradle-plugin

darylteo / vertx-gradle-plugin

Vert.xプロジェクトを作る際は、vert-x / vertx-gradle-template を使うのが公式で推奨されています。

今回は、非公式ではありますが、Gradleのpluginがあったので試して見ました。

ただ、scalaだけ使いたいのにgroovyのサポートが無いとまともに動かない、modzipにしたものの依存関係のjarが足りない等、まだ未成熟な箇所が見受けられました。

しかし、build.gradleだけでほぼ動作可能な環境を作れるのは、やはりありがたいので今後のアップデートと公式の採用を期待したいと思います。

成果

最終的に出来たスライドはこちら↓

http://grimrose.github.io/shibuya-java-05-5

おわりに

Vert.xの概要等は、@muraken720 さんのスライドを見ていただくのが一番だと思っていたので、紹介させて頂きました。

あと、Vert.x がいいね!(第1回:入門する) がまとまっていて読みやすいので、 Vert.xって何だろと興味を持たれた方は、是非読んでください。

Java 8がリリースされ、個人的にVert.xで期待しているのはNashornなのです。

NashornによってRhino以上のパフォーマンスを得られることが出来れば、あのNode.jsに匹敵するプラットフォームになるのではと考えてます。

もう一つは、Node.JS for the JVMと銘打つ Nodyn です。

この2つが今年のVert.xで一番期待できるコンテンツだと思うので、注目して行きたいと思います。

]]>
Wed, 09 Apr 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/02/15/introduction_of_afterburner_fx.html http://grimrose.bitbucket.org/blog/html/2014/02/15/introduction_of_afterburner_fx.html <![CDATA[afterburner.fxで始めるJavaFX]]> afterburner.fxで始めるJavaFX

afterburner.fxとは

afterburner.fx は、CoCをベースとし、さらにDIを持つJavaFX用のMVP(Model-View-Presenter) frameworkです。

GitHubはこちらです。-> AdamBien / afterburner.fx

(2014-02-15 追記)

テンプレート作成後に、fxmlのファイル名を修正する作業を追加しました。

対応策としてfxmlのファイル名を全て小文字にする事で、解決しました。

step0. プロジェクトの作り方

プロジェクトのテンプレートは、pledbrook / lazybones を利用して作ると簡単です。

lazybonesは、GVM でインストールすることが出来ます。

$ gvm install lazybones

lazybonesがインストール出来たら、以下のコマンドを実行すると、lazybonesで利用できるテンプレート一覧が表示されます。

$ lazybones list
Available templates in pledbrook/lazybones-templates:

    gaelyk
    ratpack
    groovy-lib
    ratpack-lite
    java-basic
    dropwizard
    groovy-app
    afterburnerfx
    lazybones-project
    spring-boot-actuator

では、早速、afterburner.fxのプロジェクトを作ります。

$ lazybones create afterburnerfx ShibuyaJava05
Creating project from template afterburnerfx (latest) in 'ShibuyaJava05'
Cleaning up unclosed ZipFile for archive /Users/grimrose/.lazybones/templates/afterburnerfx-1.0.0.zip
Define value for 'group' [org.example]: org.grimrose        # グループ
Define value for 'version' [0.1.0-SNAPSHOT]: 0.1.0-SNAPSHOT # バージョン
Define value for 'packageName' [org.grimrose]: org.grimrose # パッケージ名
Define value for 'afterburnerVersion' [1.1]: 1.4.1          # afterburner.fxのバージョン

Afterburner.fx project template
-------------------------------

You've just created a basic [Afterburner.fx][afterburner.fx] application. It provides the
standard project structure and simple configurations for both [Gradle][gradle] and
[Maven][maven] to build and run the project.

The project's structure is laid out as follows

    <proj>
      |
      +- src
          |
          +- main
              |
              +- java
              |
                 // application sources
              |
              �+- resource
              |
                 // FXML and CSS

To compile and run the application with Gradle

    gradlew run

To compile and run the application with Maven

    mvn jfx:run

Additional information on specific settings for Gradle and Maven plugins can be found on
ther respective sites

 * [javafx-gradle][]
 * [javafx-maven][]

[gradle]: http://www.gradle.org
[maven]: http://maven.apache.org
[javafx-gradle]: https://bitbucket.org/shemnon/javafx-gradle
[javafx-maven]: http://zenjava.com/javafx/maven
[afterburner.fx]: http://afterburner.adam-bien.com


Project created in ShibuyaJava05!

これでプロジェクトの雛形が作られました。ファイル構成は、以下のように生成されます。

$ tree
.
├── README.md
├── build.gradle
├── gradle
│   ├── javafx.gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── pom.xml
└── src
    └── main
        ├── java
        │   └── org
        │       └── grimrose
        │           ├── ShibuyaJava05Main.java
        │           ├── ShibuyaJava05Presenter.java
        │           ├── ShibuyaJava05Service.java
        │           └── ShibuyaJava05View.java
        └── resources
            └── org
                └── grimrose
                    └── shibuyaJava05.fxml

10 directories, 14 files

では、このままアプリケーションを立ち上げてみます。

$ gradle run

こんな感じで起動したでしょうか。

../../../_images/step1.png

では、一旦終了して、次にIntelliJ IDEAのプロジェクトへ変換して取り込んでみましょう。

step1. IntelliJ IDEAで開発する準備

今回作成したプロジェクトは、grimrose / shibuya-java-05 にあります。

IntelliJ IDEAに取り込む前に、各種ライブラリのversionを上げておきます。

afterburner.fxは、javafx-gradle を利用しているので、最新の0.4.0へ更新します。

まず、gradle/javafx.gradle の以下の箇所を修正します。

//apply from: 'http://dl.bintray.com/content/shemnon/javafx-gradle/0.3.0/javafx.plugin'
apply from: 'http://dl.bintray.com/content/shemnon/javafx-gradle/0.4.0/javafx.plugin'

次に、Gradle Wrapperのversionを上げておきます。

build.gradle に以下のコードを追加します。

wrapper {
    gradleVersion = '1.10'
}

最後に、以下のコマンドを実行してプロジェクトへ変換します。

$ gradle wrapper
$ gradle idea

(2014-02-15 追記)

キャメルケースでプロジェクトを作成した場合、fxmlのファイル名も同様になってしまいます。

しかし、fxmlファイルを読み込む際に、全て小文字のパッケージ名 + ファイル名で読み込む 様になっているため、変更します。

$ mv src/main/resources/org/grimrose/shibuyaJava05.fxml src/main/resources/org/grimrose/shibuyajava05.fxml

step2. Viewを作る

今回は、以下のようなアプリケーションを作ってみます。

../../../_images/app.png

まずは、src/main/resources/org/grimrose/shibuyajava05.fxmlJavaFX Scene Builder で編集します。

IntelliJ IDEAであれば、ポップアップメニューの「Open Scene Builder」から起動できます。 起動しない場合、「Preferences」で「JavaFX」で検索したあと「Path to Scene Builder」にScene Builderの場所を登録します。

今回追加するのは、以下の3つです。

  • TableView
  • TableColumn(送信日時)
  • TableColumn(メッセージ)
../../../_images/table.png

step3. Modelを作る

今回は、Message(入力されたメッセージのオブジェクト)とMessageRow(メッセージを表示に利用するオブジェクト)をそれぞれ分けて作ってみます。

それぞれのオブジェクトを表示するために、src/main/java/org/grimrose/ShibuyaJava05Presenter.java を変更します。

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;

import javax.inject.Inject;
import java.text.DateFormat;
import java.util.Date;

public class ShibuyaJava05Presenter {

    public ObservableList<MessageRow> messageRowList = FXCollections.observableArrayList();

    @FXML
    TableView<MessageRow> table;

    @FXML
    TableColumn<MessageRow, String> submitAtColumn;

    @FXML
    TableColumn<MessageRow, String> messageColumn;

    @FXML
    void initialize() {
        table.setEditable(false);
        submitAtColumn.setCellValueFactory(new PropertyValueFactory<MessageRow, String>("submitAt"));
        messageColumn.setCellValueFactory(new PropertyValueFactory<MessageRow, String>("message"));

        Message message = new Message(new Date(), "ようこそ");

        String submitAt = DateFormat.getDateTimeInstance().format(message.getSubmitAt());
        MessageRow row = new MessageRow(submitAt, message.getMessage());

        messageRowList.add(row);

        table.setItems(messageRowList);
    }

        // ... 省略 ...
}

それでは、表示できるのか確認してみましょう。

../../../_images/view_model.png

step4. Serviceを作る

次に、PresenterがModelを呼ぶ際に使うServiceオブジェクトを作ってみます。

import java.text.DateFormat;

public class MessageRowService {

    public MessageRow create(Message message) {
        String submitAt = DateFormat.getDateTimeInstance().format(message.getSubmitAt());
        return new MessageRow(submitAt, message.getMessage());
    }

}
import java.util.Date;

public class MessageService {

    public Message create(String inputMessage) {
        return new Message(new Date(), inputMessage);
    }

}

PresenterがServiceを呼んで使えるようにします。ここでServiceに Injectアノテーション を付けることで、DIすることが出来ます。

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;

import javax.inject.Inject;

public class ShibuyaJava05Presenter {

    public ObservableList<MessageRow> messageRowList = FXCollections.observableArrayList();

    @FXML
    TableView<MessageRow> table;

    @FXML
    TableColumn<MessageRow, String> submitAtColumn;

    @FXML
    TableColumn<MessageRow, String> messageColumn;

    @Inject
    MessageRowService messageRowService;

    @Inject
    MessageService messageService;

    @FXML
    void initialize() {
        table.setEditable(false);
        submitAtColumn.setCellValueFactory(new PropertyValueFactory<MessageRow, String>("submitAt"));
        messageColumn.setCellValueFactory(new PropertyValueFactory<MessageRow, String>("message"));

        Message message = messageService.create("ようこそ");
        MessageRow row = messageRowService.create(message);

        messageRowList.add(row);

        table.setItems(messageRowList);
    }

    // ... 省略 ...
}

step5. Eventを編集する

入力したメッセージを画面に表示できるように変更します。

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;

import javax.inject.Inject;

public class ShibuyaJava05Presenter {

    // ... 省略 ...

    @FXML
    private TextField inputMessage;

    public void submitMessage(ActionEvent event) {
        ObservableList<MessageRow> currentList = table.getItems();

        Message message = messageService.create(inputMessage.getText());
        MessageRow row = messageRowService.create(message);

        currentList.add(row);
        inputMessage.setText("");
    }

}

Presenterの修正に合わせて、src/main/resources/org/grimrose/shibuyajava05.fxml も修正します。

その後起動して、メッセージを入力してボタンを押すと、こんな感じになります。

../../../_images/input_message.png

step6. 仕上げ

気づいた方もいらっしゃると思いますが、起動するとメッセージに以下のメッセージが表示されているかと思います。

Can't find bundle for base name org.grimrose.shibuyajava05, locale ja_JP

ResourceBundleを使って、ラベルの表示を変更します。

まず、以下の内容の src/main/resources/org/grimrose/shibuyajava05.properties を追加します。

title=Message
label=Input Message
submit=submit
datetime=submit at
messages=messages

IntelliJ IDEAであれば、 空の src/main/resources/org/grimrose/shibuyajava05_ja.properties を追加すると、ResourceBundleのタブが表示され、日本語対応のpropertiesファイルを編集できます。 詳しくは、そこは,やっぱりIntelliJ使っとこうよ をご覧ください。

src/main/resources/org/grimrose/shibuyajava05.fxml でベタ書きしていたラベルの箇所を編集して、利用していないServiceを削除して完了です。

最後に

Java7u51からセキュリティレベルが上がった為か、assembleタスクで生成されたjarから起動出来なくなったので、解決策を知っている方がいらっしゃればお教え下さい。

(2014-02-15 追記)

@aoetk さんから教えて頂きました。ありがとうございます。

原因となった箇所は、ここのようです。

セキュリティアップデートとは関係ありませんでした。申し訳ありません。

他にもJavaFXでDIをしたい場合、GuiceをJavaFXで使えるようにする cathive / fx-guice がありますので、こちらも参考にしてみてはいかがでしょうか。

JavaFXも作りやすい環境がだいぶ整って来ていますし、Event周りの無名クラスもJava8のlambdaによってだいぶ見やすくなると思いますので、試してみてはいかがでしょうか。

]]>
Sat, 15 Feb 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2014/01/29/vert_x_module_registry.html http://grimrose.bitbucket.org/blog/html/2014/01/29/vert_x_module_registry.html <![CDATA[Vert.x Module Registryへの登録]]> Vert.x Module Registryへの登録

まずはじめに

Vert.x Module Registrygrimrose / fluent-logger-vertx を公開したので、その方法を紹介したいと思います。

Vert.x からデータを Fluentd に流したかったので、 fluent / fluent-logger-java をラップしたModuleを作成しました。

Vert.x Moduleとは、Useful Vert.x components and modules のように出来る限り疎結合にし、繋げて使えるようにしてあるライブラリのことです。

Vert.x Moduleの作り方

Modules Manual を参考にModuleを作成しますが、再利用可能にするために mod.json へ必要事項を記載します。

mod.json についての詳細は Module descriptor file - mod.json を参照してください。

ここでは、公開時に必要になってくる項目を挙げます。

{
    "description": "Text description of what the module does",
    "licenses": ["JSON array of licenses used in the module"],
    "author": "Main author of the module (individual or organisation)"
}

以下の項目は、オプションですが、書いておくと検索に引っかかりやすくなると思います。

{
    "developers": ["JSON array of keywords that describe the module - these are used when searching."],
    "homepage": "URL of the project website",
    "keywords": ["JSON array of other developers of the module."],
}

完成した mod.json は以下のような内容です。

{

    "main": "org.grimrose.vertx.mods.FluentLoggerModule",
    "worker": true,

    "description": "Fluentd Logger Module for Vert.x",
    "licenses": ["The Apache Software License Version 2.0"],
    "author": "grimrose",

    "developers": ["grimrose"],
    "keywords": ["fluentd", "logger"],
    "homepage": "https://github.com/grimrose/fluent-logger-vertx",

    "auto-redeploy": true

}

Bintray でModuleを公開するためのzipファイルは、以下のタスクで生成します。

$ gradle clean modZip

ビルドが成功すると、以下の場所に生成されます。

$ ls build/libs/

Bintrayで公開

Vert.x Module RegistryHow do I get my module in Maven Central or bintray?Bintray への公開手順が載っています。

Bintray の概要については、GradleでBintrayにアップロードする手順 を参考にしてください。

流れとしては以下の通りです。

  1. vertx-mods という Repository を作成する。
  2. パッケージ名Package を作成する。
  3. リリースするバージョンVersion を作成する。
  4. リリースするバージョンFiles タブにて パッケージ名 のディレクトリを追加する。
  5. ディレクトリ配下に Vert.x Moduleの作り方 で作成した パッケージ名-version.zip ファイルをアップロードする。
  6. Publish を選択し、公開する。

公開が終わると以下のような構成になります。

https://bintray.com/grimrose/vertx-mods/fluent-logger-vertx/0.1.0/files

(2014-06-01 追記)

URLが変更されていました。

https://bintray.com/grimrose/vertx-mods/fluent-logger-vertx/0.1.0/view/files/fluent-logger-vertx

Vert.x Module Registryへ申請

Vert.x Module RegistryRegister your module にある registration form をクリックするとフォームが表示されるので、以下の項目を入力します。

  • Name
    • 今回は、Bintrayに公開してあるものを登録するので、 owner~module-name~version を入力します。
    • ですので、grimrose~fluent-logger-vertx~0.1.0 と入力します。
  • Location
    • 今回は、Bintrayに公開してあるものを登録するので、 Bintray を選択します。
  • 最後に Verify and submit for moderation のボタンを押すと申請出来ます。

Bintrayへの公開に失敗していたり、既に申請してある場合等、不備がある場合はエラーになります。

登録されると検索できるようになりますので、登録されるまでしばらく時間がかかるみたいなので待ちましょう。

Bintrayを使った公開手段を用意しているので、RubyやPython、JavaScriptといったMaven Centralに縁の無い人も使えるようになっているが嬉しいですね。

Vert.x Moduleのインストール

登録されれば、Installing modules manually from the repository を参考に、以下のコマンドでインストールすることが出来ます。

$ vertx install owner~module-name~version

また、Deploying a module programmatically を参考に、アプリケーションのVerticleに記載することで、自動的にデプロイされます。

container.deployModule("owner~module-name~version", config)

Let’s enjoy Vert.x life !

]]>
Wed, 29 Jan 2014 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/12/23/kotlin_advent_calendar_2013.html http://grimrose.bitbucket.org/blog/html/2013/12/23/kotlin_advent_calendar_2013.html <![CDATA[KotlinをVert.xで呼んでみた]]> KotlinをVert.xで呼んでみた

この記事は、Kotlin Advent Calendar 2013 の23日目として書かれたものです。

22日目は @clomie さんの KAnnotatorでJavaライブラリでもNull-Safety機能を使う #Kotlin です。

24日目は、すから枠 Shinsuke-Abe さんの ことりんはスカラスキーの愛人になりうるか です。

きっかけ

Vert.x についての概要は 内部から見たVert.xとNode.jsとの比較 をご覧ください。

今回はPolyglotつまり多言語対応について注目してみます。

Vert.xの記事を探していたところ Kotlin in action: wrapping vert.x を見つけたので、動かしてみようと思います。

KotlinをVert.xで利用する

Vert.xのプロジェクトは vertx-gradle-template を元に作ります。

まず、 KotlinのGradleプラグイン を参考にGradleでKotlinを使えるようにします。

build.gradle に以下のコードを追加します。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
    }
}

apply plugin: "kotlin"

ライブラリの依存関係は、以下のようにしました。 Kotlinのversionとgradle pluginのversionが一致している為、他のライブラリと同様に gradle.properties で管理します。

dependencies {

    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"

    // twitterを利用するので
    compile 'org.twitter4j:twitter4j-core:3.0.5'

    // 日付変換に利用
    compile 'org.apache.commons:commons-lang3:3.1'

    // twitter4jのモックを作る為
    testCompile 'org.mockito:mockito-all:1.9.5'

    // 今回mainにGroovyを利用する為
    provided "org.codehaus.groovy:groovy-all:$groovyVersion"
    provided "io.vertx:lang-groovy:$groovyLangModVersion@jar"

}

test.testClassesDir = project.tasks.compileTestKotlin.destinationDir

次に、 src/main/kotlin のディレクトリを作成します。

次に、gradle idea と実行すれば、先ほど作成したkotlinディレクトリがソースディレクトリとして認識された状態のIntelliJ IDEAのプロジェクトが作られます。

今回のサンプルを作るに当たって、Kotlinを全く触ったことが無かったので、昨年のAdvent Calendarを参考にさせて頂きました。

24日目:ツイート検索アプリをつくる

その他に参考にさせて頂いたのは、以下のサイトです。

初めは、上記の記事を元に Verticle (Vert.xのモジュールを構成する最小の単位)を作って試行錯誤して見ましたが、 どうやら、Vert.xのversionが上がった為か上手く動かすことが出来ませんでした。

そこで、Kotlinで作られたクラスをGroovyのVerticleから呼び出すようにしました。

今回のサンプルは、こちらです。

https://github.com/grimrose/KotlinAdventCalendar2013

Twitter4J に渡すOAuthアクセストークンを conf.json に入力します。

{
    "OAuthConsumerKey": "Consumer key",

    "OAuthConsumerSecret": "Consumer secret",

    "OAuthAccessToken": "Access token",

    "OAuthAccessTokenSecret": "Access token secret"
}

gradle runMod を実行し、http://localhost:8080 で実行可能です。

感想

Kotlinを初めて触った感想としては、Javaと一緒に使おうとするといろいろと、Javaに引きずられている面があるなと感じました。 純粋にKotlinだけで書くと別の印象を受けると思います。

JavaからKotlinのコードを使う場合も、そんなに難しいとは思いませんでした。 ただ、まだ試した程度なので、本格的に使うとなると別の側面が出てくるかもしれません。

個人的にKotlinで面白いと思ったのは、 Function literals です。 Javaのクラスでは扱いづらいのも、この仕組みを利用することで使いやすくなるのではないかと思います。

Java8から導入される機能が、どんな影響をうけるか分かりませんが使いやすい言語になっていって欲しいです。

最後に

Providing Support for a New Language with Vert.x

Vert.xのPolyglotを支えているのは、このモジュール構成のおかげでもあります。

ですので、Kotlinもやろうと思えば、mod-lang-kotlinが作れてしまうわけです。

もし興味がある方は、挑戦してみてはいかがでしょうか。

]]>
Mon, 23 Dec 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/12/14/g__advent_calendar_2013.html http://grimrose.bitbucket.org/blog/html/2013/12/14/g__advent_calendar_2013.html <![CDATA[Gradle Vagrant Pluginについて]]> Gradle Vagrant Pluginについて

この記事は、G*(Groovy, Grails ..) Advent Calendar 2013 の14日目として書かれたものです。

13日目は @kyon_mm さんの Groovyでデバッグするとき です。

15日目は @nobeans さんの Grails/Gradleの「さっきのテストレポート」をAlfredに表示してもらう です。

Gradle Vagrant Pluginとは

皆さんもちろん Vagrant 使って開発していらっしゃると思いますが、Gradle から使えるともっと便利なのになぁと思ったことはありませんか?

私はあります。

今回、そんなあなたに紹介するPluginは gradle-vagrant-plugin です。

はじめに

このpluginの出来る事は、CLIからVagrantを利用する際のコマンドをタスクとして実行できることです。

どうしても開発やテストの際に、複数のboxでやりたいけど、コマンドラインから入れるの面倒な場合ありますよね。

そういう時、タスクを動的に作れるGradleなら出来るんじゃないかとか思ったわけです。

多分、世界には、同じような事を思った人間が必ずいると思ったので検索したところ見つけました。

導入

  • Vagrantのインストール

まずはじめに、Vagrantをインストールしてください。

INSTALLING VAGRANT

http://docs.vagrantup.com/v2/installation/index.html

  • build.gradleについて

次に、build.gradle に以下のコードを追加します。

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'org.gradle.api.plugins:gradle-vagrant-plugin:0.2'
    }
}

apply plugin: 'vagrant'

主なタスクはこちらです。 -> https://github.com/bmuschko/gradle-vagrant-plugin#tasks

  • Extensionについて

Extensionで必要な項目は、以下のように vagrant のClosureで書きます。

vagrant {
    boxDir = file('.')
}

boxDir は、必ず指定しなければならないみたいです。

Vagrantのコマンドを実行する場所なので、もし別のディレクトリで実行するのであれば、そちらを指定してください。

provider は、デフォルトは virtualbox が指定されていますので、別のproviderを使用する場合は、別のを指定してください。

  • タスクを追加する場合

org.gradle.api.plugins.vagrant.tasks.Vagrant がタスクのクラスになっているので、利用する場合はtypeに指定してください。

標準ではprovisionコマンドに対応したタスクが無いので追加してみましょう。

import org.gradle.api.plugins.vagrant.tasks.Vagrant

task vagrantProvision(type: Vagrant) {
    commands = ['provision']
}

commandsList<String> なので、気をつけてください。

最後に

GradleでVagrantを利用できるようになってから、他のタスクと組み合わせることが出来るようになったので、いろいろと自動化出来るようになったと思います。

今回のサンプルは、こちらです。 -> https://github.com/grimrose/vagrant-puppet-vertx-sample

Yokohama.groovy #20 で途中になっていたプロジェクトを利用してみました。

宣伝

現在、@shinyaa31 さんが主催されていた #yokohamagroovy を引き継いで、開催しております。

過去のイベントについてはこちらをご覧ください。 -> Yokohama.groovy

以下に該当する方で、興味がありましたら、よろしくお願いします。

  • Groovyを初めてみたいけど、どうしたらいいのか分からない。
  • Javaを使っているけど、もう少しカジュアルに使いたい。
  • GroovyでJavaのテスト書けるって聞いたから使ってみたい。
]]>
Sat, 14 Dec 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/12/03/java_advent_calendar_2013.html http://grimrose.bitbucket.org/blog/html/2013/12/03/java_advent_calendar_2013.html <![CDATA[FluentLeniumの紹介について]]> FluentLeniumの紹介について

この記事は、Java Advent Calendar 2013 の3日目として書かれたものです。

2日目は Mogami さんの Stream APIの始め方 です。

4日目は @khasunuma さんの 日本人のためのDate and Time API Tips です。

FluentLeniumとは

今回紹介するのは、SeleniumのWebDriverを流れるようなインターフェース(fluent interface)で実装できるようにしたテスティングフレームワークです。

FluentLenium / FluentLenium

assertionのライブラリとして、JUnit , FEST-Assert が利用できます。

はじめに

先日開催された システムテスト自動化カンファレンス2013 #stac2013 に参加してきました。

そこで行われた 実践で学ぶ、効率的な自動テストスクリプトのメンテナンス でSeleniumの基本的な使い方を学ぶことが出来ました。

独学で学んでいたため基礎となる部分を知ることが出来たのと、ハンズオンの内容を所属している会社の研修に取り入れてみたいと思ったため、とても参考になりました。

独学で学んでいた頃から思っていたのは、SeleniumのWebDriverのAPIが分かりにくく、使いづらいことでした。

もともとGroovyが好きなので Geb を個人的に使っていたのですが、会社ではGroovyを採用できる環境が無いため、勧めることが出来ませんでした。

そこで、もう少し使いやすくて、なんとかJavaで書けるフレームワークは無いものかと探していました。

FluentLeniumを知るきっかけは Play framework がこのFluentLeniumを採用しているということでした。

APIもSeleniumよりだいぶ使いやすくて、しかもJavaでも使えるので大変気に入りました。

今回は、ハンズオンの内容をFluentLeniumではどのように書けるのか紹介してみたいと思います。

導入

サンプルのレポジトリはこちらです。 grimrose / STARHandsOn

まず、 Gradle を利用して依存関係を解決します。

$ gradle init を実行して生成された build.gradle を修正します。

apply {
    plugin 'java'
    plugin 'idea'
    plugin 'eclipse'
}

repositories {
    mavenCentral()
}

dependencies {
    // AssertionのライブラリとしてFEST-Assertを利用
    testCompile 'org.fluentlenium:fluentlenium-festassert:0.9.1'

    // JUnitの場合、fluentlenium-coreを選択
    //testCompile 'org.fluentlenium:fluentlenium-core:0.9.1'
    testCompile 'junit:junit:4.11'
}

// testのディレクトリの配置が特殊なため
sourceSets {
    test {
        java {
            srcDir 'test'
        }
    }
}

test {
    // Gradleのtestタスク実行時に今回追加したファイルのみを対象とするように指定。
    include 'practicework_fluent/**'
}

利用するIDEに合わせて、 $ gradle idea または $ gradle eclipse を実行してプロジェクトを作成してください。

基本的な使い方

FluentLeniumは、 org.fluentlenium.adapter.FluentTest を継承してテストクラスを作成します。

デフォルトのWebDriverはFirefoxの為、ChromeのDriverを利用するには FluentTest#getDefaultDriver() をオーバーライドします。

FluentLeniumの特徴

Fluent#find() の引数に tag, id, class などのCSSセレクターを指定することで、対象となる要素を取得できます。

さらに Fluent#find() のショートカットとして、Fluent#$() が用意されているのでjQueryの様に記述する事が可能です。

パラメータを入力するには Fluent#fill() の引数にCSSセレクターを指定することで、対象となるinput要素に値をセットすることが出来ます。

その他に Fluent#click() などが用意されています。

WebDriverのAPIが使いたい場合は、FluentWebElement#getElement() で呼び出して使うことも出来ます。

// id:dayscountの内容を取得する。
find("#dayscount").getText();

// id:datePickの値を取得する。
$("#datePick").getValue();

// id:reserve_yearに"2013"を入力する場合
fill("#reserve_year").with("2013");

// id:reserve_termのプルダウンに”1”を入力する場合
fillSelect("#reserve_term").withValue("1");

// id:breakfast_onのラジオボタンをクリックする場合
click("#breakfast_on");
$("#breakfast_on").click();

// id:datePickで見つかった初めの要素にEnterKeyを入力する場合
$("#datePick").first().getElement().sendKeys(Keys.RETURN);

Page Object Pattern

FluentLeniumは、Page Object Patternを利用する為に org.fluentlenium.core.FluentPage を用意しています。

FluentPageは org.fluentlenium.core.Fluent を継承しているため、ほぼFluentTestと同じように利用できます。

ほぼ同じ事が出来てしまう為、Page Objectの責務を考慮して作成する必要があります。

また、FEST-Assertと組み合わせた場合、IDEの補完機能が優れている と、サクサクと書くことが出来ます。

見た目もJasmineやRSpecに似たような書き方が出来るので、何となく文章のように見えます。

// id:datefromの内容が"2013年12月8日"と一致するか
assertThat(confirmPage.dateFrom()).isEqualTo("2013年12月8日");
// id:guestname
assertThat(inputPage.$("#guestname").getValue()).isEmpty();

例えばテストを書き進めていく途中で、上記のような書き方をした後に、リファクタリングし、Page Objectへ移動するといったことが出来ます。

最後に

FluentLeniumは、Groovyと組み合わせるとさらにコード量を減らすことが出来ます。

test-groovy のディレクトリに幾つかGroovyを使って書いてみたものがありますので、参考になればと思います。

FluentLeniumの残念な点があるとすれば、WebDriverを複数切り替えたい場合、かなり大変だと言う点です。

JUnitのRule annotationと上手く組み合わせることが出来れば、もっと使いやすくなると思います。

先述のGebには そういった機能 があるので、もし複数のWebDriverを使いたくて、Groovyが採用できるのであれば、Gebをお勧めします。

また、FluentLeniumはcucumberとも連携できるみたいなので、興味のある方は是非試して公開してくださるとありがたいです。

以上、Seleniumでつらい思いをされた方は、ちょっとは楽になる FluentLenium を試してみてはいかがでしょうか?というお誘いでした。

追記

@garbagetown さんが Selenium Advent Calendar 2013 の四日目にFluentLeniumについて書いてくださいました。

FluentLenium http://garbagetown.hatenablog.com/entry/2013/12/04/115048

被ってしまい申し訳ありません…

併せてご覧ください。

]]>
Tue, 03 Dec 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/07/20/how_to_use_watchdog_continuous_test_plugin.html http://grimrose.bitbucket.org/blog/html/2013/07/20/how_to_use_watchdog_continuous_test_plugin.html <![CDATA[watchdog-continuous-test-pluginの紹介]]> watchdog-continuous-test-pluginの紹介

Watchdog Continuous Test Plugin https://bitbucket.org/grimrose/watchdog-continuous-test-plugin

きっかけ

Gradle を使ってRubyの Guard のようなにファイル監視をする方法は無いかと思い、Gradleプラグインを作ってみました。

自分自身guardを使ったことが無いので、同じようなことが出来ているのか分かりませんが、やりたかった 「ファイル監視 + testタスクの実行」 は実現出来たので公開してみました。

必須事項

java.nio.fileを利用しているので、Java7が必要になります。

使い方

まず、build.gradle にプラグインを使えるように buildscript を追加します。

buildscript {
    repositories {
        maven {
            url "http://oss.sonatype.org/content/repositories/snapshots/"
        }
    }
    dependencies {
        classpath group: 'org.bitbucket.grimrose', name: 'watchdog-continuous-test-plugin', version: '1.0-SNAPSHOT'
    }
}

apply plugin: 'watchdog-continuous-test'

次に監視の対象にするファイルやディレクトリと実行するタスクを指定します。

今回は、Javaプロジェクトのsrcディレクトリを対象に、testタスクを実行するように指定します。

watchdog {
    tasks = ['test']
    dirs = sourceSets*.allSource*.srcDirs.flatten()
}

準備が出来たので、実行してみましょう。

実行するタスクは watching です。

$ gradle watching

gradle wrapperの場合は、こちら

$ gradlew watching

これで、ファイルを追加されたり、変更があった場合にtestタスクが実行されます。

中断する場合は、Ctrl + C で終了してください。

最後に

今回のプラグインを作成するにあたって、参考にさせて頂いたサイトは以下の通りです。

maven centralへの公開方法についていろいろアドバイスしてくださった @mike_neck さん、ありがとうございました。

]]>
Sat, 20 Jul 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/07/07/sphinx_contrib_twitter.html http://grimrose.bitbucket.org/blog/html/2013/07/07/sphinx_contrib_twitter.html <![CDATA[sphinxcontrib.twitterの確認]]> sphinxcontrib.twitterの確認

@grimrose

]]>
Sun, 07 Jul 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/05/03/verify_code_block.html http://grimrose.bitbucket.org/blog/html/2013/05/03/verify_code_block.html <![CDATA[code-blockの確認]]> code-blockの確認

試しにHelloSpockのコードを張ってみる。

/**
 * name.size() == lengthが強調される。
 */
class HelloSpock extends spock.lang.Specification {

    def "length of Spock's and his friends' names"() {
        expect:
        name.size() == length

        where:
        name     | length
        "Spock"  | 5
        "Kirk"   | 4
        "Scotty" | 6
    }

}
]]>
Fri, 03 May 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/05/03/second_post.html http://grimrose.bitbucket.org/blog/html/2013/05/03/second_post.html <![CDATA[second post]]> second post

日本語で書けるかな?

]]>
Fri, 03 May 2013 00:00:00 +0900
http://grimrose.bitbucket.org/blog/html/2013/05/03/first_post.html http://grimrose.bitbucket.org/blog/html/2013/05/03/first_post.html <![CDATA[first post]]> first post

Hello Tinkerer!

]]>
Fri, 03 May 2013 00:00:00 +0900