SlideShare ist ein Scribd-Unternehmen logo
1 von 21
Downloaden Sie, um offline zu lesen
階層化Javaプロパティ
             ファイルDSL作成 JRuby編
             2012/04/04 akimatter

12年4月5日木曜日
自己紹介
             秋間武志

             @akimatter

             Java10年、Ruby6年

             Ruby Business Commons運営委員

             株式会社グルーヴノーツ
             テクニカルプロデューサー/プログラマ

12年4月5日木曜日
要件
                                                 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日木曜日
cascading_properties


         名前重要

         ライブラリ名 cascading_properties

         モジュール名 CascadingProperties




12年4月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日木曜日
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'
      end


12年4月5日木曜日
設計



12年4月5日木曜日
オブジェクトの関連
               ツリー構造にマッピングできそう
      compiler {
        error {
           message {
              varNotFound "variable not found"
              incompatibleType "incompatible type"
           }
        }
        maxReport 10
        files {
           input.encoding "SJIS"
           output.encoding "UTF-8"
        }
      }

12年4月5日木曜日
Object#method_missing
             メソッド
       オブジェクトに定義されていないメソッドが呼び出
       された際に呼び出されるフックメソッド。

       呼び出されたメソッド名とそれに渡された引数とブ
       ロックが、method_missingの引数とブロックとして
       渡される。




12年4月5日木曜日
メソッドのコンテキスト
        compiler {
             error {
                       message {
                                                                  メソッドはその
                           varNotFound "variable not found"
                           incompatibleType "incompatible type"
                                                                  外側のノードを
                       }                                          selfとするコン
             }
             maxReport 10                                         テキストで呼び
             files {
                                                                  出される
                     input.encoding "SJIS"
                     output.encoding "UTF-8"

             }
        }

12年4月5日木曜日
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年4月5日木曜日
もっとも重要な部分
   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日木曜日
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
   end



12年4月5日木曜日
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
     end




12年4月5日木曜日
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日木曜日
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
       end



12年4月5日木曜日
おまけ



12年4月5日木曜日
設定ファイルで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日木曜日
簡単に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)
                  end



12年4月5日木曜日
ソースコード


             https://github.com/akm/cascading_properties

               rspecでテストも書いてあるよ




12年4月5日木曜日

Weitere ähnliche Inhalte

Andere mochten auch (6)

1
11
1
 
Assess 2012 dragon 11 preview dsa11
Assess 2012 dragon 11 preview dsa11Assess 2012 dragon 11 preview dsa11
Assess 2012 dragon 11 preview dsa11
 
Graficas esquipos de futbol
Graficas esquipos de futbolGraficas esquipos de futbol
Graficas esquipos de futbol
 
Test
TestTest
Test
 
Ejercicio 13 04-2012 powerpoint
Ejercicio 13 04-2012 powerpointEjercicio 13 04-2012 powerpoint
Ejercicio 13 04-2012 powerpoint
 
Peter Rosdahl om trender på SXSW 2012
Peter Rosdahl om trender på SXSW 2012Peter Rosdahl om trender på SXSW 2012
Peter Rosdahl om trender på SXSW 2012
 

Ähnlich wie DSL by JRuby at JavaOne2012 JVM language BoF #jt12_b101

20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
Masanori Kado
 
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
linzhixing
 
ちょっと詳しくJavaScript 第2回【関数と引数】
ちょっと詳しくJavaScript 第2回【関数と引数】ちょっと詳しくJavaScript 第2回【関数と引数】
ちょっと詳しくJavaScript 第2回【関数と引数】
株式会社ランチェスター
 
実践プログラミング DSL
実践プログラミング DSL実践プログラミング DSL
実践プログラミング DSL
Nemoto Yusuke
 
Puppet Best Practices? at COOKPAD
Puppet Best Practices? at COOKPADPuppet Best Practices? at COOKPAD
Puppet Best Practices? at COOKPAD
Gosuke Miyashita
 
第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)
Masanori Machii
 
Node.js Error & Debug Leveling
Node.js Error & Debug LevelingNode.js Error & Debug Leveling
Node.js Error & Debug Leveling
kumatch kumatch
 
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
JPCERT Coordination Center
 
次世代DaoフレームワークDoma
次世代DaoフレームワークDoma次世代DaoフレームワークDoma
次世代DaoフレームワークDoma
Toshihiro Nakamura
 
Scala.jsはじめました?
Scala.jsはじめました?Scala.jsはじめました?
Scala.jsはじめました?
K Kinzal
 

Ähnlich wie DSL by JRuby at JavaOne2012 JVM language BoF #jt12_b101 (20)

20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
 
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
 
ちょっと詳しくJavaScript 第2回【関数と引数】
ちょっと詳しくJavaScript 第2回【関数と引数】ちょっと詳しくJavaScript 第2回【関数と引数】
ちょっと詳しくJavaScript 第2回【関数と引数】
 
Patterns and Matching in Rust
Patterns and Matching in RustPatterns and Matching in Rust
Patterns and Matching in Rust
 
実践プログラミング DSL
実践プログラミング DSL実践プログラミング DSL
実践プログラミング DSL
 
Puppet Best Practices? at COOKPAD
Puppet Best Practices? at COOKPADPuppet Best Practices? at COOKPAD
Puppet Best Practices? at COOKPAD
 
第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)
 
Project lambda
Project lambdaProject lambda
Project lambda
 
Node.js Error & Debug Leveling
Node.js Error & Debug LevelingNode.js Error & Debug Leveling
Node.js Error & Debug Leveling
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門
 
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
 
Ruby メタプログラミングによるXMLテンプレートエンジンの実装と評価
Ruby メタプログラミングによるXMLテンプレートエンジンの実装と評価Ruby メタプログラミングによるXMLテンプレートエンジンの実装と評価
Ruby メタプログラミングによるXMLテンプレートエンジンの実装と評価
 
次世代DaoフレームワークDoma
次世代DaoフレームワークDoma次世代DaoフレームワークDoma
次世代DaoフレームワークDoma
 
Beginners Scala in FAN 20121009
Beginners Scala in FAN 20121009Beginners Scala in FAN 20121009
Beginners Scala in FAN 20121009
 
Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値
 
Scala.jsはじめました?
Scala.jsはじめました?Scala.jsはじめました?
Scala.jsはじめました?
 
Mysql casual talks vol4
Mysql casual talks vol4Mysql casual talks vol4
Mysql casual talks vol4
 
分散ストリーム処理フレームワーク Apache S4
分散ストリーム処理フレームワーク Apache S4分散ストリーム処理フレームワーク Apache S4
分散ストリーム処理フレームワーク Apache S4
 
Reladomo in Scala #scala_ks
Reladomo in Scala #scala_ks Reladomo in Scala #scala_ks
Reladomo in Scala #scala_ks
 
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングpi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
 

Mehr von Takeshi AKIMA (8)

20120831 mongoid
20120831 mongoid20120831 mongoid
20120831 mongoid
 
LT at JavaOne2012 JVM language BoF #jt12_b101
LT at JavaOne2012  JVM language BoF #jt12_b101LT at JavaOne2012  JVM language BoF #jt12_b101
LT at JavaOne2012 JVM language BoF #jt12_b101
 
20120324 git training
20120324 git training20120324 git training
20120324 git training
 
20120121 rbc rails_routing
20120121 rbc rails_routing20120121 rbc rails_routing
20120121 rbc rails_routing
 
Llonsen object ruby
Llonsen object rubyLlonsen object ruby
Llonsen object ruby
 
jrubykaigi2010-lt-rubeus
jrubykaigi2010-lt-rubeusjrubykaigi2010-lt-rubeus
jrubykaigi2010-lt-rubeus
 
Oktopartial Introduction
Oktopartial IntroductionOktopartial Introduction
Oktopartial Introduction
 
仕事で使ってるプラグイン
仕事で使ってるプラグイン仕事で使ってるプラグイン
仕事で使ってるプラグイン
 

DSL by JRuby at JavaOne2012 JVM language BoF #jt12_b101

  • 1. 階層化Javaプロパティ ファイルDSL作成 JRuby編 2012/04/04 akimatter 12年4月5日木曜日
  • 2. 自己紹介 秋間武志 @akimatter Java10年、Ruby6年 Ruby Business Commons運営委員 株式会社グルーヴノーツ テクニカルプロデューサー/プログラマ 12年4月5日木曜日
  • 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. cascading_properties 名前重要 ライブラリ名 cascading_properties モジュール名 CascadingProperties 12年4月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. 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' end 12年4月5日木曜日
  • 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. Object#method_missing メソッド オブジェクトに定義されていないメソッドが呼び出 された際に呼び出されるフックメソッド。 呼び出されたメソッド名とそれに渡された引数とブ ロックが、method_missingの引数とブロックとして 渡される。 12年4月5日木曜日
  • 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. 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日木曜日
  • 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. 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 end 12年4月5日木曜日
  • 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   end 12年4月5日木曜日
  • 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. 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 end 12年4月5日木曜日
  • 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. 簡単に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)     end 12年4月5日木曜日
  • 21. ソースコード https://github.com/akm/cascading_properties rspecでテストも書いてあるよ 12年4月5日木曜日