こんなのがあったので、便乗。
datomicチュートリアルの今日のエントリーのednファイル、心のこもった手作りのednファイルを作るのが、元からハートフルな精神のない僕には辛い作業だったので、groovyで書いてた。で、groovyで書くなら、書きやすいようにやりたい。ということで、groovyのdslを作ってやってました。
上記の渡辺さんの記事では最後の方にいい感じに実装していれば云々ってあったのですが、dslの実装ってあまり例を見かけないので、groovyでdslを書くときの参考に、このクソ記事書いています。
で、このエントリーで実行したいdslはこれ。
おい 1 たす 1 は 2 だろ jk おい 1 たす 1 は 1だろ jk
ちなみに、このdsl、きよたかさんがだれかjggugの人がやったやつで、groovy界隈の人にはかなり有名。
で、これの実装は次のような感じ。
def おい = {int left -> [たす: {int right -> [は: {int expected -> [だろ: {Object anything -> try { assert left + right == expected } catch (AssertionError e) { throw new AssertionError("おい ${left} たす ${right} は ${expected} だろ jk\n${e.message}") } }] }] }] } def jk = null
では、おもむろに実行!
java.lang.AssertionError: おい 1 たす 1 は 1 だろ jk assert left + right == expected | | | | | 1 2 1 | 1 false
では、この書き方を利用して、ednファイルを作り出す実装を書いてみましょう。
enum Region { NE(':region/ne'), SW(':region/sw'), N(':region/n'), S(':region/s') private final String v Region(String v) { this.v = v } String asKey() {v} static Region random() { def r = values() return r.collect {it}[new Random().nextInt(r.size())] } } enum CommunityType { Twitter('twitter'), Facebook('facebook-page'), Wiki('wiki') final String type CommunityType(String type) { this.type = type } String asKey(){":community.type/${type}"} static CommunityType random() { def c = values() return c.collect{it}[new Random().nextInt(c.size())] } } enum OrgType { Community, Commercial String asKey() {":community.orgtype/${this.toString().toLowerCase()}"} static OrgType random() { def o = values() return o.collect {it}[new Random().nextInt(o.size())] } } assert Region.random() in Region.values() assert CommunityType.random() in CommunityType.values() assert OrgType.random() in OrgType.values() abstract class Entity { static String DB_ID = ':db/id' final long dbId = { def id = new Random().nextLong() id < 0 ? id : -id }() String toDbId() { "#db/id[:db.part/user ${dbId}]" } } class District extends Entity { static String ENTITY = ':district' String name Region region @Override String toString() { def dq = '"' $/{${DB_ID} ${toDbId()}, ${ENTITY}/name $dq$name$dq, ${ENTITY}/region ${region.asKey()}}/$ } } class Neighborhood extends Entity { static String ENTITY = ':neighborhood' String name District district @Override String toString() { def dq = '"' $/{${DB_ID} ${toDbId()}, ${ENTITY}/name $dq$name$dq, ${ENTITY}/district ${district.toDbId()}}/$ } } class Community extends Entity { static String ENTITY = ':community' static String DQ = '"' String name String url List<String> categories String category() { "[${categories.collect {"$DQ$it$DQ"}.join(' ')}]" } OrgType orgType CommunityType type Neighborhood neighborhood @Override String toString() { $/{$DB_ID ${toDbId()}, $ENTITY/name $DQ$name$DQ, $ENTITY/url $DQ$url$DQ, $ENTITY/category ${category()}, $ENTITY/orgtype ${orgType.asKey()}, $ENTITY/type ${type.asKey()}, $ENTITY/neighborhood ${neighborhood.toDbId()}}/$ } } class Data { def list = [] Data self = this def community = {String cn -> [url: {String cu -> [category: {List<String> cc -> [orgtype: {OrgType co -> [type: {CommunityType ct -> [neighbor: {String nn -> [district: {String dn -> [region: {Region rr -> def district = new District(name: dn, region: rr) def neighborhood = new Neighborhood(name: nn, district: district) def community = new Community(name: cn, url: cu, categories: cc, orgType: co, type: ct, neighborhood: neighborhood) list << [district: district, neighborhood: neighborhood, community: community] return [next:{ return self }] }] }] }] }] }] }] }] } @Override String toString() { $/[ ${list.collect{ it.collect { it.value.toString() } }.flatten().join('\n')} ]/$ } } def data = new Data() data.community('Foo') .url('http://localhost:8000/foo') .category(['test']) .orgtype(OrgType.Commercial) .type(CommunityType.random()) .neighbor('Hoo') .district('Koo') .region(Region.random()) .next() .community('Hoge') .url('http://localhost:8000/hoge') .category(['test', 'kudoh']) .orgtype(OrgType.Commercial) .type(CommunityType.random()) .neighbor('Kan Java') .district('Kansai') .region(Region.random()) println data
data
以下の部分は横一列で書けば、ドットも括弧もいらないんだけど、読みづらくなるので、改行してドット入れて、括弧つけた。
以上、クソコード屋からは以上です。