FizzBuzz
Groovy
メタプログラミング

FizzBuzzクイズの実装例(groovy)

問題と、ruby による実装例は
https://qiita.com/sumim/items/f26902f2b813c075a619

で。

なんとなく、Groovy なら行けるかもと思って実装してみた。

def val( int x ){  x }
def val( String x ){ x.val() }

def stringof( int x ){ "" }
def stringof( String x ){ x }

[
  ["fizz", "Fizz", {x->x%3==0}],
  ["buzz", "Buzz", {x->x%5==0}],
  ["pezz", "Pezz", {x->x%7==0}],
  ["hozz", "Aho", {x->x.toString().contains("3")}],
].each{ o->
  this.metaClass."${o[0]}" = { x->
    if ( o[2](val(x)) ){
      r=stringof(x)+o[1]
      r.metaClass.val{ return val(x) }
      return r
    } else {
      return x
    }
  }
}

println( fizz(buzz(1) )) //=> 1
println( fizz(buzz(pezz(3*5*7) ))) //=> PezzBuzzFizz
println( fizz(hozz(3) )) //=> AhoFizz

やっぱり書けた。さすが Groovy。

  • メソッドの動的定義
  • 特異メソッド

という辺りは拙実装の ruby 版( https://qiita.com/Nabetani/items/9c477fd222412f11e29b )と同じだけど、

  • 引数の型によるメソッドの呼び分け

という辺りは Groovy ならではの技。頼もしい。

DRY でしょ?

追記。
buzz(fizz(123)) 形式ではなく、 123.fizz.buzz 形式にも対応したバージョンを実装した。

def val( int x ){  x }
def val( String x ){ x.val() }

def stringof( int x ){  "" }
def stringof( String x ){  x }

[
  ["fizz", "Fizz", {x->x%3==0}],
  ["buzz", "Buzz", {x->x%5==0}],
  ["pezz", "Pezz", {x->x%7==0}],
  ["hozz", "Aho", {x->x.toString().contains("3")}],
].each{ o->
  Object.metaClass["get"+o[0]] = { ->"${o[0]}"(delegate) }
  this.metaClass."${o[0]}" = { x->
    if ( o[2](val(x)) ){
      r=stringof(x)+o[1]
      r.metaClass.val{ return val(x) }
      return r
    } else {
      return x
    }
  }
}

println( 1.buzz.fizz ) //=> 1
println( (3*5*7).fizz.buzz.pezz ) //=> FizzBuzzPezz
println( 31.fizz.buzz.pezz.hozz ) //=> Aho
println( 33.fizz.buzz.pezz.hozz ) //=> FizzAho
println( 63.fizz.buzz.pezz.hozz ) //=> FizzPezzAho
println( 3.hozz.pezz ) // => Aho

Object にメソッドを追加することで IntegerString の両方に対応するというやや鬼畜の所業に出てみた。

Groovy の文字列は Java の文字列なので、同じ値は同じインスタンスになりがち。メソッドを生やすと同じ値の文字列はそのことを憶えていたりするのかなとも思ったけど、そうでもない感じだった。なんでだろ。