忍者ブログ
[2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]

DATE : 2017/06/27 (Tue)
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。


DATE : 2008/04/19 (Sat)

配布用 ZIP ファイルなどのパッケージを構築できる Maven Assembly Plugin を Maven 2.0.9をインストールした後に実行すると、Maven 2.0.8以前とは違ったパッケージができあがってしまいました。

例えば、次のような Assembly Descriptor があったとします。(「...」は省略を表します)

...
  <dependencySets>
  
    <dependencySet>
      <outputDirectory>/lib</outputDirectory>
      <outputFileNameMapping>${artifactId}.${extension}</outputFileNameMapping>
    </dependencySet>

  </dependencySets>
...

この Assembly Descriptor は、プロジェクトが依存するライブラリなどのプロジェクトを、lib ディレクトリに「(アーティファクト名).(拡張子)」というファイル名で格納するという指定をしています。

ところが、この記述のある Assembly Descriptor を Maven 2.0.9 で実行すると、想定とは異なるファイルが lib ディレクトリに格納されていました。例えば、sample-project というアーティファクト名のプロジェクトがあり、commons-logging というプロジェクトに依存している場合、正しく動作すれば lib ディレクトリの直下に commons-logging.jar というファイルが格納されるはずです。ところが、なぜか sample-project.${extension} というファイルができていました。

Maven Assembly Plugin のページを確かめてみると、Mave Assembly Plugin のバージョンアップによって Assembly Descriptor の仕様が変わったようです。特に、上の例で該当する「outputFileNameMapping」要素の説明には、次のように書いてありました。

Sets the mapping pattern for all dependencies included in this assembly. Default is ${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}. (Since 2.2-beta-2; 2.2-beta-1 uses ${artifactId}-${version}${dashClassifier?}.${extension}) The default value is ${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}.

つまり、Maven Assembly Plugin 2.2-beta-1 と Maven Plugin 2.2-beta2 とでは、 outputFileNameMapping の書き方が異なるということです。

Maven 2.0.9 では Maven Assembly Plugin 2.2-beta-2 が採用されています(Maven 2.0.9 の Super POM)。そのため、自動的に Maven Assembly Plugin も 2.2-beta-2 にバージョンアップされます。そのため、Maven Assembly Plugin の動作変更に対して次のいずれかの方法で対処しなければなりません。

  • Assembly Descriptor を Maven Assembly Plugin 2.2-beta-2 の仕様にあわせて書き直す。
  • POM に Maven Assembly Plugin 2.2-beta-1 を使うようにバージョンを指定する。

(;^ω^)仕様が変わるなら、Maven のリリースノートに書いてほしかったですね。

PR

DATE : 2008/04/13 (Sun)

システム専用のディレクトリを使用するシステムを開発していると、ディレクトリの指定方法に迷うことがあります。例えば、Hibernate を用いて全文検索を行うことのできる Hibernate Search では、インデックスをディレクトリに格納するため、そのディレクトリをプロパティであらかじめ指定しておかなければなりません。

こういった環境に依存する設定があちこちの設定ファイルやプロパティに散らばっていると、管理が大変です。そこで、Maven Resources Plugin のフィルタリング機能が使えます。この機能の使い方は、次の通りです。

  1. resources ディレクトリ以下のファイル中の置換したい文字列を${...}に置き換える。
  2. プロジェクト設定ファイル(pom.xml)に置換するプロパティを指定する。
  3. プロジェクトをビルドする。

resources ディレクトリ以下のファイル中の置換したい文字列を${...}に置き換える

例えば、resources ディレクトリ中のファイルに次のような設定があったとします。

<property name="hibernate.search.default.indexBase" value="c:/index" />

ここで、value 属性の値はディレクトリへのパスになっています。今回は、この部分をフィルタリング機能で置き換えます。置き換えのために、value 属性の値を${indexBase}に書き換えます。

<property name="hibernate.search.default.indexBase" value="${indexBase}" />

プロジェクト設定ファイル(pom.xml)に置換するプロパティを指定する

続いて、プロジェクト設定ファイル(pom.xml)の中に次の内容を追加します。(「...」は省略を表します)

<project>
...
  <properties>
    <indexBase>c:/index</indexBase>
  </properties>
...
</project>

つまり、project タグ直下に properties タグを書き、properties タグの直下に置き換え対象の文字列のタグを作ります。

プロジェクトをビルドする

以上で、フィルタリング機能を使う準備は終わりです。Maven Resources Plugin は、初期設定でビルドサイクルから自動的に呼び出されるため、プロジェクトをビルドするだけで、resources ディレクトリ以下の${...}で指定された文字列が自動的に置換されます。

参考文献


DATE : 2008/04/05 (Sat)

R の関数を書くときには、使い方などのコメントを関数の内側に書くと便利です。

R で関数オブジェクトを呼び出すと、その関数のソースコードが表示されます。例えば、次のような関数があったとします。

# 引数同士を足し合わせる。
#
# 引数:
#   a : 足される数
#   b : 足す数
# 戻り値:
#   a と b を足し合わせた数
add <- function(a, b) {
    # 計算結果を返す
    return(a + b)
}

この関数オブジェクトを次のように呼び出すと、次のように関数のソースコードが表示されます。(「>」はプロンプトです)

> add
function(a, b) {
    # 計算結果を返す
    return(a + b)
}

ここで、関数の使い方を記した関数外部のコメントは消えていますが、内部のコメントは残っていることに気づきます。

そこで、関数の使い方を関数内部に入れてしまいます。

add <- function(a, b) {
# 引数同士を足し合わせる。
#
# 引数:
#   a : 足される数
#   b : 足す数
# 戻り値:
#   a と b を足し合わせた数

    # 計算結果を返す
    return(a + b)
}

このようにすると、関数オブジェクトを呼び出したときに関数の使い方も分かって便利です。

> add
function(a, b) {
# 引数同士を足し合わせる。
#
# 引数:
#   a : 足される数
#   b : 足す数
# 戻り値:
#   a と b を足し合わせた数

    # 計算結果を返す
    return(a + b)
}

(;^ω^)これまでは、Java などの癖で関数定義の上に書いていました。ところがある日、関数内部のコメントが残っていることに気づき、R の関数のコメントは関数内部に書くようにしました。


DATE : 2008/03/29 (Sat)

The Art of UNIX Programming」(Eric S.Raymond 著、長尾高弘 訳、アスキー、2007)を読みました。UNIX の設計やそれをとりまくコミュニティの伝統から、「UNIX では、なぜそうなっているのか」を解説する本です。

こういった、これまでにあるものを例として、その本質を抜き出して解説するという本は珍しかったので、面白かったです。特に、テキスト形式のデータの重要性を説いた部分では、実際に使われているデータファイルや、POP3 などの通信プロトコルを例として具体的に説明しています。さすがに、長年使われてきただけあって、説得力がありました。

また、マルチスレッドプログラミングに関しても面白い記述がありました。マルチスレッドプログラミングのやっかいな問題として、スレッド間で共有されているデータが挙げられます。書き換えられるタイミングを調整するのがとても難しいため、本書ではマルチプロセスへの分割を推奨しています。例えば、サーバとクライアントに分けられる場合は、サーバプロセスとクライアントプロセスに分割してプロセス間通信を行うことで、データの保護を行います(例として、PostgreSQL や X サーバなどが挙げられています)。

本書によると、そもそも UNIX の世界にはマルチスレッドの考え方がなかったようです。そのため、普段 Windows を使っている身としてはこの部分は非常に驚きました。確かに、マルチスレッドとは異なり、マルチプロセスの場合は、データへのアクセス方法がプロセス間通信に限られます。まさに、情報隠蔽の考え方だと思いました。

また、オープンソースに関わる方法についても触れられています。例えば、SourceForge などからダウンロードしたパッケージを展開すると、だいたい似通ったディレクトリ構成になっていることに気づきます。この構成は長年培われてきたもので、その意味やその理由について詳しく述べられています。また、パッチの送り方などにも触れられており、オープンソースに関わる際には貴重な指針となりそうです。

実際に使われているアプリケーションや言語などを基に解説されているため、例に用いられている中には、すでに古いものもあります。しかし、そこから抽出された本質はなかなか変わるものではありません。そのため、記述されているアプリケーションがこれから使われなくなったとしても、当分は役に立つ本と言えそうです。


DATE : 2008/03/14 (Fri)

データフレームから条件式が成り立つ行のみを抽出する subset という関数があります。例えば、result データフレームの「x」という列の値が0を超える行のみを抽出するには、次のようなコードを実行します。(「>」や「+」はプロンプトです)

> subset(result, 0 < x)

通常、データフレームの列にアクセスするには、「result$x」とするか、「result['x']」としなければなりません。ただ単に x と書いても、x という名前のオブジェクトが参照されるだけです。ところが、subset 関数の場合は、条件式に当たる部分では自動的にデータフレームのオブジェクトを補ってくれます。そのため、subset 関数の条件式の部分では、ただ単に列名のみを書くだけで十分です。

このような subset 関数を R で直接実行する分には、なんの問題もありません。ところが、あるとき subset を内部で使う関数を書いていたときに、はたと困ってしまいました。条件式の渡し方が分からなかったのです。例えば、次のような関数を実行しようとしても、失敗してしまいます。

> subset_function <- function(condition) {
+     subset(result, condition)
+ }

> subset_function(0 < x) 
 以下にエラー eval(expr, envir, enclos) :  オブジェクト "x" は存在しません 

R では、式は必要になるまで評価されません。そのため、subset_function に渡した条件式は評価されずに関数内部に入ります(遅延評価)。ところが、関数内部の subset の部分で評価が失敗しているようです。

しばらく悩んだところ、次のような解決策が思い浮かびました。

> subset_function <- function(condition) {
+     subset(result, eval(condition))
+ }

> subset_function(expression(0 < x))

式表現を渡して、subset のところで評価するという方法です。ところが、いまひとつスマートではありません。実際、subset 関数は expression 関数を使用せずに式を評価できています。

そこで、R 2.6.2 のソースコードから、subset 関数を定義している部分(src/library/base/R/frametools.R)を調べてみました。条件式の評価に関わる部分のみを抜き出すと、次のようになります。「(...)」は省略を表します。

subset.data.frame <- function (x, subset, select, drop = FALSE, ...)
{
    (...)
    e <- substitute(subset)
    r <- eval(e, x, parent.frame())
    (...)
}

subset 関数の定義を診ると、条件式(subset)は、substitute 関数に渡され、その結果が eval 関数に渡されています。まず、substitute 関数によって式を解析木オブジェクトに変換しています。そして、eval 関数によって、その解析木を渡されたデータフレームの環境で、そのデータフレームは親の呼び出しスタックから取得するという処理になっています。eval の引数は少々分かりづらかったのですが、引数として渡されたデータフレームに対して評価を行う際の書き方であると、eval 関数のヘルプに書かれていました。subset_function は、引数でデータフレームを受け取ってはいませんが、親の呼び出しスタックにあるデータフレームを関数内で直接使っています。そのため、データフレームの取得に親の呼び出しスタックを使用しています。

subset 関数の定義が上のようになっていたので、subset_function も次のように書き直せます。

> subset_function <- function(condition) {
+     e <- substitute(condition)
+     r <- eval(e, result, parent.frame())
+     subset(result, r)
+ }

> subset_function(0 < x)

このようにすることで、条件式をそのまま使用できるようになりました。

注意

上の関数の内容を、以下のように1行にまとめた場合はうまく動作しません。

> subset_function <- function(condition) {
+     subset(result, eval(substitute(condition), result, parent.frame()))
+ }

subset 関数の引数となる eval 関数や、その引数となる substitute 関数は、遅延評価のために、その関数の実行される呼び出しスタックが、subset 関数以下になります。そのため、result のある呼び出しスタックがうまく呼び出せずに失敗するようです。

忍者ブログ [PR]
ブログ内検索
最近の状況
リンク
カレンダー
05 2017/06 07
S M T W T F S
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
使用許諾
最新コメント
(08/15)
(05/04)
(03/06)
(03/04)
(09/25)
最新トラックバック
T/O
(11/05)
ブログ内検索
最近の状況
リンク
カレンダー
05 2017/06 07
S M T W T F S
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
使用許諾
最新コメント
(08/15)
(05/04)
(03/06)
(03/04)
(09/25)
最新トラックバック
T/O
(11/05)