iPhotoライブラリをDropboxで管理するときに気をつけるべきたったひとつのこと
iPhoto Libraryの中にあるOriginal、Data、Modifiedというエイリアスを削除してから共有しましょう。
なんで?
Dropboxはエイリアス経由のパスであっても気にせずに物理的にサーバ上にファイルを格納するので、画像が多重にアップロードされてしまい、サーバ利用量がヤバいことになります。というか、なった。
具体的にはどうする?
iPhoto Libraryを右クリックのアレで開いて、Original、Data、Modifiedというエイリアスを削除しましょう。Data.noindexというのがあったらそれも*1。iPhotoはこれらがなくても普通に動作しますが、万が一何かあっても自己責任でお願いします。
経緯
元々20GBも使ってないときに、40GBくらいのiPhoto Libraryを共有したら、アップロードに2〜3日かかったあと、合計で105GB使ってますよという状態になってしまったので、有料会員の特権(?)でサポートに問い合わせてみたら、FAQらしくて手順書ページを紹介されました。 対処後に一晩放っておいたら、無事に60GBぐらいに落ち着いて、サイズ保存則が無事に成立しました。
*1:自分はなかった
Gradle1.6の新機能mustRunAfterでタスク間の実行順序が制御可能になった #gradle
Gradleではタスク間の依存関係の指定ができます。
build.gradle:
task a << { println "A" } task b(dependsOn: "a") << { println "B" } task c(dependsOn:"a") << { println "C" } task d(dependsOn: ["b", "c"]) << { println "D" }
実行結果:
$ gradle d :a A :b B :c C :d D BUILD SUCCESSFUL Total time: 1.612 secs
実はこの例のBとCの間の関係は不定であり、実装に基づいて(この場合はアルファベット順だったりしたはず)実行順序が決められます。 ここではA→B→C→Dになっていますね。
しかし、このようなグラフ的には一見どっちがさきに実行されても良いようにみえるBとCの間に、実は微妙な前後関係があって、Cの方が先に実行されて欲しい!というケースは意外とありますよね。
長い間Gradleユーザから臨まれていたこの機能がついに1.6で実装されました(ということをさっき知った)!
Task#mustRunAfter()
の使い方
以下のように使います。
build.gradle:
task a << { println "A" } task b(dependsOn: "a"/*, mustRunAfter: "c" -- 残念ながら今のところここには書けないらしい*/) { mustRunAfter "c" // メソッド呼出として書く doLast { println "B" } } task c(dependsOn:"a") << { println "C" } task d(dependsOn: ["b", "c"]) << { println "D" }
と書くと、こうなります:
$ gradle d :a A :c C :b B :d D BUILD SUCCESSFUL Total time: 1.64 secs
dependsOn
との違い
実は単にA→C→B→Dとしたいだけであれば、↓と書くだけでもOKです。
task a << { println "A" } task b(dependsOn: ["a", "c"]) << { println "B" } task c(dependsOn:"a") << { println "C" } task d(dependsOn: ["b", "c"]) << { println "D" }
mustRunAfter
との違いは、タスクbを実行してみると見えてきます。
一つ前のサンプルだと:
$ gradle b :a A :c C :b B BUILD SUCCESSFUL Total time: 0.723 secs
となります。 bの依存先にcが入ってるので実行タスクのグラフにcが登場するのですね。
さて、mustRunAfter
を使った先ほどと同じこの設定で実行してみると...
task a << { println "A" } task b(dependsOn: "a") { mustRunAfter "c" doLast { println "B" } } task c(dependsOn:"a") << { println "C" } task d(dependsOn: ["b", "c"]) << { println "D" }
実行結果:
$ gradle b :a A :b B BUILD SUCCESSFUL Total time: 1.745 secs
となります。
mustRunAfter
は依存関係の指定ではなく、実行タスクのグラフ上にそのタスクが存在した場合に単にその順序関係を指定しているだけなので、この場合にはタスクcは登場しないのです!
実際どういう場面で使うの?
ふもさんのサンプルがわかりやすそうです。
task clean << { println 'cleaning.' } task build << { println 'building.' } build.doLast { println 'finish!' } task local(dependsOn: [clean, build]) << { println 'local debug.' }
これを実行するとこうなります:
$ gradle local :build building. finish! :clean cleaning. :local local debug. BUILD SUCCESSFUL Total time: 1.638 secs
build
してからclean
するとかso crazyですね。ちょっと何言ってるか分からないです。
ここで実行順序制御にdependsOn
を使おうとすると、
task clean << { println 'cleaning.' } task build(dependsOn: 'clean') << { println 'building.' } build.doLast { println 'finish!' } task local(dependsOn: [clean, build]) << { println 'local debug.' }
実行結果:
$ gradle local :clean cleaning. :build building. finish! :local local debug. BUILD SUCCESSFUL Total time: 1.605 secs
うまくいった!?ようにみえますが、clean
せずに差分ビルドさせようとbuild
タスクを指定すると...
$ gradle build :clean cleaning. :build building. finish! BUILD SUCCESSFUL Total time: 0.755 secs
clean
まで発動してしまいました!!これでは毎回フルビルドになってしまい、開発速度が上がりません。
そこで、mustRunAfter
の出番です。
build.gradle:
task clean << { println 'cleaning.' } task build { mustRunAfter 'clean' doLast { println 'building.' } } build.doLast { println 'finish!' } task local(dependsOn: [clean, build]) << { println 'local debug.' }
実行結果:
$ gradle local :clean cleaning. :build building. finish! :local local debug. BUILD SUCCESSFUL Total time: 0.722 secs
$ gradle build :build building. finish! BUILD SUCCESSFUL Total time: 1.58 secs
素晴らしい!期待通りの結果です。
というわけで、依存関係のdependsOn
と、実行順序の微調整のmustRunAfter
をうまく使い分けましょう。
コペンハーゲンのGR8Conf EU 2013でGroovyServとImproxプラグインを紹介してきた
5/22-24にデンマークはコペンハーゲンで開催されたGR8Conf EU 2013というGroovy系のカンファレンスで、GroovyServとImproxプラグインを紹介してきました。
右の写真はコペンハーゲンの定番がっかり観光スポットの「人魚の像」ですね。 がっかり感が軽減されている一枚を選びました。 まあ、どこの観光地にもがっかりスポットはつきものです。 札幌の時計台にくらべれば人魚はだいぶ良かったんじゃないでしょうか。
GR8Conf EUは今年で5周年だそうです。コペンハーゲンがオリジナルですが、「GR8Conf」ブランドのカンファレンスは別ロケーションでも何度か開かれていて、USは今年も7月にありますしほぼレギュラー化してるようですね。他に覚えているところではオーストラリアでも開催されてました。日本でも開きたいですね。
さて、自分の発表ですが、本日動画が公開され(てしまっ)たので、スライドと動画のリンクを張っておきます。 つたない英語ですがよければご笑覧ください。
- 自分の発表のポータルページ的なもの
- スライド
- 動画
当方の深刻な英語力不足にともない今回は不本意ながら「最初に言い訳」メソッドで乗り切りましたが、やっぱりせっかくやるからには「ネイティブ&インタラクティブ」方式を目指したいですね。 最後、質疑がなくて寂しい感じにみえますが、たぶんみなさん気を遣ってくれた感じで、セッション後に数名の方と技術的な話もしましたからね? *1
他の錚々たるスピーカのみなさんの動画も随時公開されていくはずなので、興味がある方はTwitterで@gr8confをフォローしておくと良いと思います。
そうそう、今度の6/21のJGGUG主催GワークショップZで、G*ワークショップZ Jun 2013 - GR8Conf報告&ライブコーディング&GroovyServ/Improxをやります。 ご興味があれば是非是非ご参加ください。
*1:どちらかというと「お前の英語は悪くない」「問題ないよ」「グレートだったぞ」みたいな慰めにきてくれた人の方が多かったですけど。
GrailsからMirageを使うサンプルがあったので試してみた
Mirageという2-way SQLが利用できる素敵なO/RマッパをGrailsで使ってみたというブログがあったので、サンプルコードを落として試してみました。
developmentモードでMySQL使うようになってたので、H2に変更してrun-appして試してみました。
確かにMirageでDB操作できている!
のですが、更新ボタン2回目を押すとuniqueエラーになるのでおかしいなと思ってみてみたら、insert.sqlファイル内に書いてあるINSERT文でIDがハードコードされてるのでそりゃ2回目は失敗しますね。idを省略して自動払い出しを期待して実行してみると、実行毎にレコードが追加できます。素晴らしい。
という感じで、コードを色々見ていたところ、気になる点が色々あったので、forkして自分好みに修正してみました。 コネクション・データソース・トランザクションまわりのための準備が煩雑だったので、その辺を重点的に頑張ってみました。これ、以外と難しくて一応うまく動いてるようだけどもそんなに自信ないです。たぶん大丈夫だと思うんだけど。 あと、テストもSpockで追加したり、もちろんimproxプラグインも追加したりして、かなり好き放題いじってます。 Grailsのバージョンも最新の2.2.2にあげちゃいました。
コミットログに日本語でゆるいコメントを残してるので何をしていったかはコミットログ参照のこと。コミットログとdiffみたらだいたい何やったか理解できるんじゃないかと。
HibernateのネイティブSQLやGroovy-SQLを使う方法で間に合うことも多いですが、2-way SQLを外部ファイルで指定できるのはSeasarの追っかけ的には嬉しいので、チャンスがあったら使ってみようかなぁ。GrailsConnectionProviderの件とかもあるのでプラグイン化も検討してみようかしら。
参考URL
- 元記事
- オレオレ版サンプル
- とそのコミットログ
- Improxプラグイン
- Mirage
- Spock
- Spockワークショップ
GrailsのGORMにおける各種関連とmappingによる名前変更のサンプル
Grailsのドキュメントを翻訳する上で、英文読んでも何を言ってるか分からないので、サンプル書いて試してみた記録です。
↓ここに反映される予定。
生成されたスキーマはPostgreSQLにて確認してあります。 異なるDBMSなら異なるスキーマになることもあるかも知れません。Hibernateのみぞ知る。
多対1/1対1関連(単方向)
基本
ドメインクラス
class Person { String firstName Address address static mapping = { table 'people' firstName column: 'First_Name' } } class Address { String number String postCode static mapping = { postCode type: 'text' } }
生成されたスキーマ
Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
address_id | bigint | not null
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "people" CONSTRAINT "fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Person上のaddressカラムのマッピングを変更してみる
ドメインクラス
class Person { String firstName Address address static mapping = { table 'people' firstName column: 'First_Name' address column: 'Person_Address_Id' // コレの効果は...? } } class Address { String number String postCode static mapping = { postCode type: 'text' } }
生成されたスキーマ
Table "public.people"
Column | Type | Modifiers
-------------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
person_address_id | bigint | not null <-------- ココが変わった!!!
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fkc4e2328fec329d0d" FOREIGN KEY (person_address_id) REFERENCES address(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "people" CONSTRAINT "fkc4e2328fec329d0d" FOREIGN KEY (person_address_id) REFERENCES address(id)
多対1/1対1関連(双方向)
基本
ドメインクラス
class Person { String firstName Address address static mapping = { table 'people' firstName column: 'First_Name' } } class Address { String number String postCode static belongsTo = [person:Person] static mapping = { postCode type: 'text' } }
生成されたスキーマ
単方向の場合とスキーマは同じ。
Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
address_id | bigint | not null
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Referenced by: TABLE "people" CONSTRAINT "fkc4e2328f2efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Person上のaddressカラムのマッピングを変更してみる
単方向の場合とスキーマは同じなので、後は...わかりますね?
1対多関連(単方向)
基本
ドメインクラス
class Person { String firstName static hasMany = [addresses: Address] static mapping = { table 'people' firstName column: 'First_Name' } } class Address { String number String postCode static mapping = { postCode type: 'text' } }
生成されたスキーマ
Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "people_address" CONSTRAINT "fk3af1764434f4e10e" FOREIGN KEY (person_addresses_id) REFERENCES people(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "people_address" CONSTRAINT "fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Table "public.people_address"
Column | Type | Modifiers
---------------------+--------+-----------
person_addresses_id | bigint |
address_id | bigint |
Foreign-key constraints:
"fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
"fk3af1764434f4e10e" FOREIGN KEY (person_addresses_id) REFERENCES people(id)
Person上のaddressesカラムのマッピングを変更してみる
ドメインクラス
class Person { String firstName static hasMany = [addresses: Address] static mapping = { table 'people' firstName column: 'First_Name' addresses column: 'Person_Address_Id' // コレの効果は...? } } class Address { String number String postCode static mapping = { postCode type: 'text' } }
生成されたスキーマ
Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes: "people_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "people_address" CONSTRAINT "fk3af17644e3b329fc" FOREIGN KEY (person_address_id) REFERENCES people(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "people_address" CONSTRAINT "fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Table "public.people_address"
Column | Type | Modifiers
-------------------+--------+-----------
person_address_id | bigint | <-------- ココが変わった!!!
address_id | bigint |
Foreign-key constraints:
"fk3af176442efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
"fk3af17644e3b329fc" FOREIGN KEY (person_address_id) REFERENCES people(id)
関連テーブル自体を指定する
ドメインクラス
class Person { String firstName static hasMany = [addresses: Address] static mapping = { table 'people' firstName column: 'First_Name' addresses joinTable: [name: 'Person_Addresses', key: 'Person_Id', column: 'Address_Id'] // コレの効果は...? } } class Address { String number String postCode static mapping = { postCode type: 'text' } }
生成されたスキーマ
Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "person_addresses" CONSTRAINT "fk8aeab389671fd1" FOREIGN KEY (person_id) REFERENCES people(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "person_addresses" CONSTRAINT "fk8aeab382efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
Table "public.person_addresses" <-------- ココが変わった!!!
Column | Type | Modifiers
------------+--------+-----------
person_id | bigint | not null <-------- ココが変わった!!!
address_id | bigint |
Foreign-key constraints:
"fk8aeab382efad9e3" FOREIGN KEY (address_id) REFERENCES address(id)
"fk8aeab389671fd1" FOREIGN KEY (person_id) REFERENCES people(id)
1対多関連(双方向)
基本
ドメインクラス
class Person { String firstName static hasMany = [addresses: Address] static mapping = { table 'people' firstName column: 'First_Name' addresses cascade: "all-delete-orphan" } } class Address { String number String postCode static belongsTo = [person:Person] static mapping = { postCode type: 'text' } }
生成されたスキーマ
関連テーブルなしに、子テーブル側に親へのIDを保持するスキーマとなる。 「双方向」であるため、晴れて子から親を参照してもOKになるので、関連テーブルを導入するまでもなく、単に親 のIDを持つスキーマ構造が採用できる、ということと推測するが...。
Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "address" CONSTRAINT "fkbb979bf49671fd1" FOREIGN KEY (person_id) REFERENCES people(id)
Table "public.address"
Column | Type | Modifiers
-----------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
person_id | bigint | not null
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fkbb979bf49671fd1" FOREIGN KEY (person_id) REFERENCES people(id)
Person上のaddressesカラムのマッピングを変更してみる
ドメインクラス
class Person { String firstName static hasMany = [addresses: Address] static mapping = { table 'people' firstName column: 'First_Name' addresses cascade: "all-delete-orphan", column: 'Person_Address_Id' // こっちに書いても効かない(エラーにならず単に無視された) } } class Address { String number String postCode static belongsTo = [person:Person] static mapping = { postCode type: 'text' person column: "my_person_id" // コレの効果は...? } }
生成されたスキーマ
hoge=# \d people Table "public.people"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "address" CONSTRAINT "fkbb979bf4576400fe" FOREIGN KEY (my_person_id) REFERENCES people(id)
hoge=# \d address
Table "public.address"
Column | Type | Modifiers
--------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
number | character varying(255) | not null
my_person_id | bigint | not null <-------- ココが変わった!!!
post_code | text | not null
Indexes:
"address_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fkbb979bf4576400fe" FOREIGN KEY (my_person_id) REFERENCES people(id)
多対多関連(双方向)
基本
ドメインクラス
class Group { String name static hasMany = [people: Person] static mapping = { table 'my_group' // PostgreSQLでは'group'テーブルを作成しようとするとエラーになる } } class Person { String firstName static hasMany = [groups: Group] static belongsTo = Group }
生成されたスキーマ
Table "public.my_group"
Column | Type | Modifiers
---------+------------------------+-----------
id | bigint | not null
version | bigint | not null
name | character varying(255) | not null
Indexes: "my_group_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "my_group_people" CONSTRAINT "fk7525b002f314e043" FOREIGN KEY (group_id) REFERENCES my_group(id)
Table "public.person"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not nullIndexes:
"person_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "my_group_people" CONSTRAINT "fk7525b0029671fd1" FOREIGN KEY (person_id) REFERENCES person(id)
Table "public.my_group_people"
Column | Type | Modifiers
-----------+--------+-----------
group_id | bigint | not null
person_id | bigint | not null
Indexes:
"my_group_people_pkey" PRIMARY KEY, btree (group_id, person_id)
Foreign-key constraints:
"fk7525b0029671fd1" FOREIGN KEY (person_id) REFERENCES person(id)
"fk7525b002f314e043" FOREIGN KEY (group_id) REFERENCES my_group(id)
外部キーカラム名を変更する
ドメインクラス
class Group { String name static hasMany = [people: Person] static mapping = { table 'my_group' people column: 'Group_Person_Id' // コレの効果は...? } } class Person { String firstName static hasMany = [groups: Group] static belongsTo = Group static mapping = { groups column: 'Group_Group_Id' // コレの効果は...? } }
生成されたスキーマ
Table "public.my_group"
Column | Type | Modifiers
---------+------------------------+-----------
id | bigint | not null
version | bigint | not null name | character varying(255) | not null
Indexes:
"my_group_pkey" PRIMARY KEY, btree (id)Referenced by:
TABLE "my_group_people" CONSTRAINT "fk7525b0027e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)
Table "public.person"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes:
"person_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "my_group_people" CONSTRAINT "fk7525b00253631627" FOREIGN KEY (group_group_id) REFERENCES person(id)
Table "public.my_group_people"
Column | Type | Modifiers
-----------------+--------+-----------
group_person_id | bigint | not null <-------- ココが変わった!!!
group_group_id | bigint | not null <-------- ココが変わった!!!
Indexes:
"my_group_people_pkey" PRIMARY KEY, btree (group_person_id, group_group_id)
Foreign-key constraints:
"fk7525b00253631627" FOREIGN KEY (group_group_id) REFERENCES person(id)
"fk7525b0027e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)
関連テーブル名を指定する
ドメインクラス
class Group { String name static hasMany = [people: Person] static mapping = { table 'my_group' people column: 'Group_Person_Id', joinTable: 'PERSON_GROUP_ASSOCIATIONS' // コレの効果は...? } } class Person { String firstName static hasMany = [groups: Group] static belongsTo = Group static mapping = { groups column: 'Group_Group_Id', joinTable: 'PERSON_GROUP_ASSOCIATIONS' // コレの効果は...? } }
生成されたスキーマ
Table "public.my_group"
Column | Type | Modifiers
---------+------------------------+-----------
id | bigint | not null
version | bigint | not null
name | character varying(255) | not null
Indexes: "my_group_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "person_group_associations" CONSTRAINT "fk9dd6e6fc7e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)
Table "public.person"
Column | Type | Modifiers
------------+------------------------+-----------
id | bigint | not null
version | bigint | not null
first_name | character varying(255) | not null
Indexes: "person_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "person_group_associations" CONSTRAINT "fk9dd6e6fc53631627" FOREIGN KEY (group_group_id) REFERENCES person(id)
Table "public.person_group_associations" <-------- ココが変わった!!!
Column | Type | Modifiers
-----------------+--------+-----------
group_group_id | bigint | not null
group_person_id | bigint | not null
Indexes:
"person_group_associations_pkey" PRIMARY KEY, btree (group_person_id, group_group_id)
Foreign-key constraints:
"fk9dd6e6fc53631627" FOREIGN KEY (group_group_id) REFERENCES person(id)
"fk9dd6e6fc7e1c21ed" FOREIGN KEY (group_person_id) REFERENCES my_group(id)
GExcelAPI 0.3 リリースしました #gexcelapi
GExcelAPI 0.3をリリースしました。
Change Log、といえるかどうか
変更点としては、以下の2点。
- POI3.9化
- Java7対応 (thanks to @yamap_55)
これだけ?
はい、これだけです。
でも、Java7対応重要です。ですよね?
オレオレMavenリポジトリの移転
あと、今後の使うときの注意点として大事なのが、オレオレMavenリポジトリの移転です。 今までMavenリポジトリとしてGitHubのrawモードを使った疑似リポジトリを使っていましたが、今回からCloudBeesのリポジトリを使うようにしてみました。 既存の0.1、0.2もなんとなくそっちにコピーしてありますので、ひとまず今後はCloudBeesをお使いください*1。
release (stableバージョン)
https://repository-kobo.forge.cloudbees.com/release
snapshot (SNAPSHOTバージョン)
https://repository-kobo.forge.cloudbees.com/snapshot
ごくシンプルなサンプルコードはこんな感じ:
@GrabResolver(name="kobo", root="https://repository-kobo.forge.cloudbees.com/release")
@Grab("org.jggug.kobo:gexcelapi:0.3")
import org.jggug.kobo.gexcelapi.GExcel
def book = GExcel.open(args[0])
assert book.sheets[0].A1.value == "Sheet1-A1"
機能的に網羅したサンプルコードはテストコードを参照のこと:
CellRange#toHtml()の対応状況?
あと、以前に紹介した実験的機能としてのCellRange#toHtml()は以前の通り実験的機能としての位置づけでそのまま含まれています。 シンプルではないシートの場合にまともに動かないことも多いかもしれませんが、実験的と言うことでご了承ください。 なお、パッチ等は大歓迎です。 というか、Windows上のExcelを使う機会が大変少なくなっている昨今なので、むしろコミッタ募集です。
*1:そのうちまた変わるかもしれませんが
IntelliJ IDEAの細かすぎてわかりづらいGroovyサポート:メソッドシグネチャのホバー表示
メソッドコール部分をホバーするとAPIドキュメントを表示してくれるのはIDEとして普通のことだけど、 Groovyのような言語ではメソッドシグネチャで型を明示指定してないことが良くあります。 そういう場合でも、呼出先で使われるプロパティやメソッドなどを使ってどんなオブジェクトを期待しているか、可能な限りわかりやすく表示してくれる。
と、言葉で書いても何を言ってるかわからないだろうから、例を書くと
def hoge(foo, bar, String baz) {
foo.name = ""
println foo.value
bar.toString()
baz.toString()
}
def zzzz() {
hoge()
}
というメソッドがあるときに、zzzzのhoge()の上でカーソルをホバーしてみると(自分の環境だとCommand押しながらホバーでした)....
String hoge (foo.[name, value], bar.toString(), String baz)
と表示されます。
わかります?
- fooはnameとvalueというプロパティが使われてるので、そういうオブジェクト渡せよ
- barはtoString()メソッドが呼ばれてるので、そういうオブジェクト渡せよ
- bazはString型のインスタンス渡せよ
ということが分かります。
長いメソッドだと色んなプロパティ・メソッドが列挙されすぎてすごいことになるんじゃないか!?と心配になりますが、さすがに3つめあたりで省略記法になるようです。
Object hoge (foo.[name, value, ...], bar.toString(), String baz)
インテリジェイアイデアすごい。