階層化Javaプロパティ             ファイルDSL作成 JRuby編             2012/04/04 akimatter12年4月5日木曜日
自己紹介             秋間武志             @akimatter             Java10年、Ruby6年             Ruby Business Commons運営委員             ...
要件                                                 compiler {                                                   error {   ...
cascading_properties         名前重要         ライブラリ名 cascading_properties         モジュール名 CascadingProperties12年4月5日木曜日
ノードの名前はメソッド      compiler {        error {           message {              varNotFound "variable not found"              ...
specはこんな感じ       valid_source1 = <<-EOS         compiler {           error {             message {               varNotFou...
設計12年4月5日木曜日
オブジェクトの関連               ツリー構造にマッピングできそう      compiler {        error {           message {              varNotFound "varia...
Object#method_missing             メソッド       オブジェクトに定義されていないメソッドが呼び出       された際に呼び出されるフックメソッド。       呼び出されたメソッド名とそれに渡された引数...
メソッドのコンテキスト        compiler {             error {                       message {                                         ...
BlankSlate       Objectクラスには予めたくさんのメソッドが定義さ       れているので、多くの語彙をmethod_missingで扱え       るようにするためには、既存のメソッドができるだ       け定義され...
クラスの構成12年4月5日木曜日
もっとも重要な部分   class CascadingProperties::Node < CascadingProperties::BlankSlate     def method_missing(name, *args, &block) ...
java.util.Propetiesへの出力   class CascadingProperties::Node < CascadingProperties::BlankSlate     def to_properties(dest = n...
java.util.Propetiesへの出力     def to_properties(dest = nil, parent = nil)       dest ||= java.util.Properties.new       @_ha...
java.util.Propetiesへの出力     def to_properties(dest = nil, parent = nil)       dest ||= java.util.Properties.new       @_ha...
java.util.Propetiesも拡張できる       require java       require cascading_properties       java.util.Properties.instance_eval d...
おまけ12年4月5日木曜日
設定ファイルでERBを    compiler {      error {        message {          varNotFound "variable not found"          incompatibleTyp...
簡単にERBも使えるように                  def load_file(filepath)                    load(File.read(filepath))                  end  ...
ソースコード             https://github.com/akm/cascading_properties               rspecでテストも書いてあるよ12年4月5日木曜日
Upcoming SlideShare
Loading in …5
×

DSL by JRuby at JavaOne2012 JVM language BoF #jt12_b101

1,161 views

Published on

JavaOne 2012 JVM言語BoF プログラミング大会 - DSL
階層化JavaプロパティファイルDSL作成 JRuby編

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,161
On SlideShare
0
From Embeds
0
Number of Embeds
22
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

DSL by JRuby at JavaOne2012 JVM language BoF #jt12_b101

  1. 1. 階層化Javaプロパティ ファイルDSL作成 JRuby編 2012/04/04 akimatter12年4月5日木曜日
  2. 2. 自己紹介 秋間武志 @akimatter Java10年、Ruby6年 Ruby Business Commons運営委員 株式会社グルーヴノーツ テクニカルプロデューサー/プログラマ12年4月5日木曜日
  3. 3. 要件 compiler { error { message { varNotFound= compiler.error.message.varNotFound=... incompatibleType= compiler.error.message.incompatibleType=... } compiler.error.maxReport= } compiler.files.input.encoding= maxReport= compiler.files.output.encoding= files { input.encoding= output.encoding= } } のように擬似的に階層的に書けると、より読みやすくなることが考えられ る。このような、プロパティファイルのキーを階層構造で記述できるDSLを 作成する事とする。12年4月5日木曜日
  4. 4. cascading_properties 名前重要 ライブラリ名 cascading_properties モジュール名 CascadingProperties12年4月5日木曜日
  5. 5. ノードの名前はメソッド compiler { error { message { varNotFound "variable not found" アンダースコアがついて incompatibleType "incompatible type" いるPropertiesのキーの } } 一部となる部分は、Ruby maxReport 10 files { ではメソッドとして書け input.encoding "SJIS" output.encoding "UTF-8" る。 } }12年4月5日木曜日
  6. 6. specはこんな感じ   valid_source1 = <<-EOS compiler { error { message { varNotFound "variable not found" incompatibleType "incompatible type" } } maxReport 10 files { input.encoding "SJIS" output.encoding "UTF-8" } } EOS subject{ CascadingProperties.load(valid_source1) } it "should export to java.util.Properties" do     props = subject.to_properties     props.should be_a(java.util.Properties)     props.size().should == 5     props.getProperty("compiler.error.message.varNotFound" ).should == "variable not found"     props.getProperty("compiler.error.message.incompatibleType").should == "incompatible type"     props.getProperty("compiler.maxReport").should == 10     props.getProperty("compiler.files.input.encoding").should == SJIS     props.getProperty("compiler.files.output.encoding").should == UTF-8 end12年4月5日木曜日
  7. 7. 設計12年4月5日木曜日
  8. 8. オブジェクトの関連 ツリー構造にマッピングできそう compiler { error { message { varNotFound "variable not found" incompatibleType "incompatible type" } } maxReport 10 files { input.encoding "SJIS" output.encoding "UTF-8" } }12年4月5日木曜日
  9. 9. Object#method_missing メソッド オブジェクトに定義されていないメソッドが呼び出 された際に呼び出されるフックメソッド。 呼び出されたメソッド名とそれに渡された引数とブ ロックが、method_missingの引数とブロックとして 渡される。12年4月5日木曜日
  10. 10. メソッドのコンテキスト compiler { error { message { メソッドはその varNotFound "variable not found" incompatibleType "incompatible type" 外側のノードを } selfとするコン } maxReport 10 テキストで呼び files { 出される input.encoding "SJIS" output.encoding "UTF-8" } }12年4月5日木曜日
  11. 11. BlankSlate Objectクラスには予めたくさんのメソッドが定義さ れているので、多くの語彙をmethod_missingで扱え るようにするためには、既存のメソッドができるだ け定義されていないクラスを使う。このようなクラ スをBlankSlateと呼ぶ。 class CascadingProperties::BlankSlate   used = %w[instance_eval send class to_s hash inspect respond_to? should]   regexp = Regexp.new("/^__|^=|^%|", used.map{|m| "^#{m}$"}.join(|) + /)   instance_methods.each { |m| undef_method m unless m =~ regexp } end 定義時にused以外のメソッドをundef_methodして無 かったことにしている。12年4月5日木曜日
  12. 12. クラスの構成12年4月5日木曜日
  13. 13. もっとも重要な部分 class CascadingProperties::Node < CascadingProperties::BlankSlate   def method_missing(name, *args, &block)     name = name.to_s     case args.length     when 0 then       @_hash[name] ||= CascadingProperties::Node.new(&block)     when 1 then       @_hash[name] = args.first     else       @_hash[name] = args     end   end end 引数の数やブロックの有無で振る舞いが異なる12年4月5日木曜日
  14. 14. java.util.Propetiesへの出力 class CascadingProperties::Node < CascadingProperties::BlankSlate   def to_properties(dest = nil, parent = nil)     dest ||= java.util.Properties.new     @_hash.each do |k, v|       key = parent ? "#{parent}.#{k}" : k       if v.respond_to?(:to_properties)         v.to_properties(dest, key)       else         dest.setProperty(key, v.to_s)       end     end     dest   end end12年4月5日木曜日
  15. 15. java.util.Propetiesへの出力   def to_properties(dest = nil, parent = nil)     dest ||= java.util.Properties.new     @_hash.each do |k, v| 引数destはデフォル       key = parent ? "#{parent}.#{k}" : k       if v.respond_to?(:to_properties) トではnil。jruby上で         v.to_properties(dest, key)       else 動く場合ならdestは         dest.setProperty(key, v.to_s)       end java.util.Propertiesを     end 生成する     dest   end12年4月5日木曜日
  16. 16. java.util.Propetiesへの出力   def to_properties(dest = nil, parent = nil)     dest ||= java.util.Properties.new     @_hash.each do |k, v|       key = parent ? "#{parent}.#{k}" : k 値がto_properties可能       if v.respond_to?(:to_properties)         v.to_properties(dest, key) ならそれを呼び出した       else         dest.setProperty(key, v.to_s) 結果を、そうでないの       end     end なら値を文字列とし     dest て 、destに   end setPropertyする12年4月5日木曜日
  17. 17. java.util.Propetiesも拡張できる require java require cascading_properties java.util.Properties.instance_eval do   def load_dsl(dsl_text)     node = CascadingProperties.load(dsl_text)     node.to_properties   end end12年4月5日木曜日
  18. 18. おまけ12年4月5日木曜日
  19. 19. 設定ファイルでERBを compiler {   error {     message {       varNotFound "variable not found"       incompatibleType "incompatible type"     } ERBを使うことで、   } 動的な値を設定ファ   maxReport <%= ENV[MAX_REPORT] %>   files { イルに記述すること     input.encoding "SJIS"     output.encoding "UTF-8" も可能。   } }12年4月5日木曜日
  20. 20. 簡単にERBも使えるように     def load_file(filepath)       load(File.read(filepath))     end     def load_file(filepath)       erb = ERB.new(IO.read(filepath))       erb.filename = filepath       text = erb.result       load(text)     end12年4月5日木曜日
  21. 21. ソースコード https://github.com/akm/cascading_properties rspecでテストも書いてあるよ12年4月5日木曜日

×