Apache Maven を使ってみよう(その 3)
Maven のプラグインについて
Maven のプラグインは主に以下のサイトで用意されている。
Maven – Available Plugins
Mojo – MojoHaus Maven Plugins Project
Exec Maven Plugin
前回の課題になっていた、Maven のビルドの実行の際に main
を実行するためには、Mojo で用意されている Exec Maven Plugin を利用する。
pom.xml
を修正する。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.mydns.akanekodou</groupId> <artifactId>MavenSample</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>MavenSample</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.4.0</version> <configuration> <mainClass>jp.mydns.akanekodou.App</mainClass> </configuration> <executions> <execution> <phase>test</phase> <goals> <goal>java</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
build
要素が新たに追加され、その直下に plugins
要素がある。Maven のプラグインにはビルドプラグインとレポーティングプラグインがあり、Exec Maven Plugin はビルドプラグインなので build
要素に追加することになる。
今回は mvn test
を実行したら自動的に mvn test exec:java
が実行されるように設定している。
mvn test
を実行すると…
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jp.mydns.akanekodou.AppTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.148 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- exec-maven-plugin:1.4.0:java (default) @ MavenSample --- Hello World! [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4.490 s [INFO] Finished at: 2015-08-27T20:57:56+09:00 [INFO] Final Memory: 11M/212M [INFO] ------------------------------------------------------------------------
確かに実行されている。
Apache Maven を使ってみよう(その 2)
Maven のビルドライフサイクル
Maven のビルドライフサイクルには多数のゴールが設定されている。ちなみにデフォルトのライフサイクルには何と
validate
,initialize
,generate-sources
,process-sources
,generate-resources
,process-resources
,compile
,process-classes
,generate-test-sources
,process-test-sources
,generate-test-resources
,process-test-resources
,test-compile
,process-test-classes
,test
,prepare-package
,package
,pre-integration-test
,integration-test
,post-integration-test
,verify
,install
,deploy
こんなにゴールが設定されている。
しかし、実際にはこれを全部使うことはない。以下、主だったものを説明する。
Apache Maven を使ってみよう(その 1)
当ブログではこれまで Apache Maven (以下、Maven) の話題は極力避けてきたが、昨今の開発事情を鑑みるに、最早 Maven なしでは開発がままならない状況になりつつある。Spring MVC では標準のビルドツールとして採用されるなど、Maven は避けては通れないものになっている。
Maven はなぜ便利なのか ?
ビルドライフサイクルの自動化
IDE を使っているとあまりピンと来ないかも知れないが、たくさんの Java のソースコードを一つ一つ手でコンパイルするのは大変な作業である。Maven でプロジェクトを管理しておけば、コマンド一つでコンパイルを含むビルドライフサイクルを全て自動化できる。
Ruby で FizzBuzz を満喫する
Scala にだいぶSAN値を削られたのでここいらで Ruby に日和ろう(苦笑)。
その 1 : Object#tap
を利用する
to_fizzbuzz = -> n { "".tap do |_| _ << "Fizz" if n % 3 == 0 _ << "Buzz" if n % 5 == 0 break n if _.empty? end } puts 1.upto(100).map(&to_fizzbuzz)
Ruby の Object#tap
はブロック内で自分自身に対して行われた破壊的変更が保証される。break
が発動するとそれらの変更を破棄して強制的に別の値を返すことが出来る。発動しなければブロック内で行われた破壊的変更を適用した自身が返ることになる。
さくっと lambda 奴を使っておくと Enumerable#map
に Proc
オブジェクトを渡す Ruby らしい書き方で処理が記述できる。
その 2 : Hash
を利用する
Scala 編で Map
を使ったやつの元ネタ。
Applicators = {3 => :Fizz, 5 => :Buzz} to_fizzbuzz = -> n { fb = Applicators.select{|_| n % _ == 0}.values.join fb.empty? ? n : fb } puts 1.upto(100).map(&to_fizzbuzz)
やってることはほぼ一緒。メソッド名が違うだけ。
その 3 : Enumerable#zip
を利用する
fizz = [nil] * 2 << :Fizz buzz = [nil] * 4 << :Buzz 1.upto(100).zip(fizz.cycle, buzz.cycle) do |n, *f| puts f.any? ? f.join : n end
ネットで見つけてきた。nil
と any
の使い方が Ruby っぽくてお気に入りである。
Scala でとことん FizzBuzz する(その 4)
最初にお詫び。前回の記事にかなり大幅な修正を加えています。再度確認をしていただけるとありがたいです。
追記 : 今回作ったソースファイル群(+ テストコード)を GitHub で公開しました。
akaneko3/FizzBuzzScala · GitHub
Scala でとことん FizzBuzz する(その 3)
さぁ、改造を続けよう。
FizzBuzz アルゴリズム再考
ちょっとひねって、次のような写像を考える。
何も書いていないところは空文字列を対応させていると考える。これを利用して、FizzBuzz のアルゴリズムを少し変更する。
- 何らかの方法で
"", "", "Fizz", "", "Buzz", "Fizz", "", "", "Fizz", "Buzz", "", "Fizz", "", "", "FizzBuzz", ...
と繰り返される列を用意する。 - 1 から順に上記の列と対応させていく(
zip
) - 上記で得られた列を順に処理していくとき、「数字と空文字列」の組み合わせのときは数字を、「数字と空でない文字列」の組み合わせのときは文字列を返すようにする。
これを Scala のトレイトを利用して抽象クラスとしてあらかじめ作っておく。
package jp.mydns.akanekodou.scala.fizzbuzz abstract class FizzBuzz { protected val fb : Stream[String] def fizzbuzz : Unit = { 1 to 100 zip fb map { case (n, "") => n case (_, s) => s } foreach println } }
Java のインターフェースと違い、Scala のトレイトにはこうした共通処理をあらかじめ実装しておくことが出来る。今回、ついでなので表示するところまでまとめて実装してみた。
2015/04/12 追記 : 今回のケースではトレイトを使う必要はありませんでした。お詫びの上、通常の抽象クラスに訂正させていただきます。
もう一つ、Scala の機能である「暗黙引数」を利用している。一見するとメソッドの引数のデフォルト値をあらかじめ与えるのと似ているが、あちらはあらかじめ引数を初期化しておかないとダメなのに対し、こちらはメソッド呼び出し時までに暗黙引数を初期化・確定させておけば良い。
Java の抽象クラスは「抽象メソッドが含まれるクラス」であるが、Scala の場合は抽象メソッドに加えて上記のような抽象フィールドを含むクラスも抽象クラスとして定義しなければならない。
2015/04/12 追記 2 : Main
に FizzBuzz 系クラスを継承させる方法が何となく行儀が悪く見えたので止めました。
その他のファイルも適宜書き換えていこう。
package jp.mydns.akanekodou.scala.fizzbuzz class FirstFizzBuzz extends FizzBuzz { def toFizzBuzz(n : Int) : String = { if (n % 3 == 0) { if (n % 5 == 0) "FizzBuzz" else "Fizz" } else if (n % 5 == 0) { "Buzz" } else { "" } } val fb = Stream.from(1).map(toFizzBuzz) }
toFizzBuzz
は最早 String
型しか返さないことが明白になった。
package jp.mydns.akanekodou.scala import jp.mydns.akanekodou.scala.fizzbuzz._ object Main extends App { (new FirstFizzBuzz).fizzbuzz }
Main.scala
がだいぶすっきりした。
いよいよ本格的に改造していくぞ !
Scala でとことん FizzBuzz する(その 2)
前回のプログラムは無事動いたかな ? では改造を始める。でもその前に…。
SBT で作ったプロジェクトを Scala IDE for Eclipse で扱えるようにする
前回までの手順で、プロジェクト直下に project
フォルダが出来ていると思う。そこに plugins.sbt
というファイルを以下の内容で作成する。
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0")
そうしたらプロジェクト直下で
> sbt eclipse
を実行する。これにより Eclipse 用の設定ファイルなどが作られ、Scala IDE for Eclipse でプロジェクトをインポートして扱うことが出来る。コーディング作業は IDE を使う方が楽なのでやっておくと良い。なお、SBT でライブラリの依存関係を変更したときは再度上記コマンドを実行しないと Eclipse 側に反映されないので注意。