乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Meta Programming - Ruby-tw

       weicat 2007-01-11

      Metaprogramming 和 Ruby

      把你的 programming Language 特化成專門對(duì)你要處理的 Domain 的語(yǔ)言( Domain Specifi Language),然後再用這種語(yǔ)言去處理你的問題。

      著名的 Lisp 駭客 Paul Graham 在駭客與畫家這本書中說:

         In Lisp, you don‘t just write your program down toward the language. you also build the language up toward your program.
      

      Ruby 也同樣的有這樣的特性。

      getter & setter

      最簡(jiǎn)單的 Metaprogramming in Ruby,就是 attr_reader, attr_writer, attr_accessor。在 Ruby 裡所有的 instance variable 都是必須用 getter 和 setter 來(lái)存取。attr_xxxx 就是用來(lái)生成這些 getter 和 setter 的。

      例如:

      class MyClass
      attr_accessor :nice
      end
      a = MyClass.new
      a.nice = 100
      puts a.nice
      

      就等同於

      class MyClass
      def nice               #getter for instance variable nice
      @nice
      end
      def nice=(num)    #setter for instance variable nice
      @nice = num
      end
      end
      a = MyClass.new
      a.nice = 100
      puts a.nice
      

      這裡有幾個(gè)要說明的地方

      1. . Ruby 中 instance variable ,前頭都有個(gè) @
      2. . getter 和 setter 的名字和 instance variable一樣
      3. . method 的名字後面有 = 表示他是 setter,於是在碰到 = 時(shí)就會(huì)去 call 這個(gè) method
      4. . attr_accessor 並不是什麼神奇的 syntax suger,而只是單純的一個(gè) method 罷了。
      5. . 在 Ruby 中, Class 的定義中也可以有 method call,所以才可以 call attr_accessor

      自己寫個(gè) attr_xxxx

      我們也可以自己寫出類似這樣的 method。比如我們常常有些 instance variable 是一個(gè) flag,在 Ruby 中會(huì)傳回真假值的 method 通常以 ? 做結(jié)尾?,F(xiàn)在希望 Ruby 幫我們自動(dòng)生成這些以 ? 結(jié)尾的 method,就是要能辦到像下面這樣:

      class Work
      attr_flag  :done ,:start
      end
      w = Work.new
      puts "Yes, the work is started" if w.start?
      puts "No, the work is not done"  if !w.done?
      

      attr_flag 的寫法如下:

      class Module
      def attr_flag(*args)
      args.each  do |sym|
      class_eval %{
      def #{sym}?
      @#{sym}
      end
      }
      end
      end
      end
      
      1. . class Module 表示我們把 Module 這個(gè) class 又打開來(lái)加上一些新的定義。在 Ruby 所有的 class 都可以打開再加入新的定義。
      2. . 所有的 class 都是 class Module 的 instance ,所以這裡我們幫 Module 加上一個(gè)新的 instance method "attr_flag",所以他會(huì)變成所有的 class 的 class method 。
      3. . args 是一個(gè)陣列,內(nèi)容是所有傳進(jìn)來(lái)的參數(shù),就是哪些 instance variable 是 flag。 args.each 是走過陣列的每一個(gè)元素(請(qǐng)參考 這篇)
      4. . class_eval 的意思就是把後面的這個(gè)字串(用 %{} 括起來(lái)的是字串),當(dāng)做是目前這個(gè) class 的內(nèi)容。
      5. . 最後面用字串代換作出程式碼

      同樣的功能用 define_method 也可以做到

      class Module
      def attr_flag(*args)
      args.each  do |sym|
      define_method("#{sym}?") { instance_variable_get "@#{sym}"}
      end
      end
      end
      

      用 define_method 好像比較簡(jiǎn)潔,但是兩種方法都有人用。

      method overload 的例子

      ruby 本身並沒有提供 method overload 的功能。因?yàn)?Ruby 是一個(gè) dynamic type 的語(yǔ)言,并具有duck typing 所以不需要像 method overload 這樣的功能。不過因?yàn)?Ruby 是非常動(dòng)態(tài)的語(yǔ)言,幫他加上 overload 的功能其實(shí)很簡(jiǎn)單。

      先來(lái)看看最我們要達(dá)到什麼效果:

      class Test
      # 這是我們要寫的 OverLoad Module
      include OverLoad
      # 一般的 method 定義
      def t1
      puts ‘original t1‘
      end
      # 直接可以用 block 來(lái) overload t1 這個(gè)函數(shù)
      # 第一個(gè)參數(shù)是要被 overload 的 method 名
      # 接下來(lái)是任意個(gè)數(shù)的參數(shù),用來(lái)指用 overload method 的參數(shù)型態(tài)(這裡是沒有指定)
      # 最後是一個(gè) block,也就是 method 的內(nèi)容
      overload :t1 do |a|
      puts a
      end
      # 當(dāng)然可以 overload 很多次
      overload :t1 do |a,b|
      puts a+b
      end
      # 這裡就有指定參數(shù)的型態(tài)了 (String, String)
      overload :t1, String, String do |a,b|
      puts "the String is #{a} #"
      end
      end
      

      下面就是 OverLoad Module:

      module OverLoad
      private
      # 這是將 overload 所接到的「參數(shù)型態(tài)(spec)」轉(zhuǎn)成一個(gè)字串
      # 這個(gè)字串在等一下動(dòng)態(tài)產(chǎn)生程式碼的時(shí)候會(huì)用到
      def self.spec_to_code(spec)
      if Integer === spec
      "args.length == #{spec}"
      elsif Array === spec
      i = -1
      spec.map {|ts| "#{ts.inspect} === args[#{i+=1}]"}.join(" && ")
      end
      end
      # included 是一個(gè) Hook Method,每當(dāng)有 class include 這個(gè) module 時(shí)
      # 這個(gè) function 就會(huì)被呼叫
      # include 這個(gè) module 的 class 會(huì)被當(dāng)成參數(shù)傳進(jìn)來(lái),也就是這裡的 the_class
      def self.included(the_class)
      #這裡幫 include 這個(gè) module 的 class 加上一些新的 method
      #the_class.class_eval { ooxx} 可以想成把 ooxx 直接寫在 the_class 的內(nèi)容裡
      the_class.class_eval do
      #新加上的函式都是 private 的比較安全
      private
      # 加上 Overload_Dispetch_Db 這個(gè) Hash
      # 用來(lái)存 method_spec 和真的 method 的對(duì)映 (其實(shí)這裡存的不是 Method,而是 Proc)
      self.const_set("Overload_Dispetch_Db", Hash.new)
      # 加上 overload 這個(gè) class method
      # 以傳入的 [method名, 參數(shù)名字] 做為 key, 將 blok 存入 Hash 之中
      def self.overload(method_id, *dispatch_spec, &block)
      dd = self.const_get("Overload_Dispetch_Db")
      if dispatch_spec ==[]
      dd[[method_id,block.arity]] = block
      else
      dd[[method_id,dispatch_spec]] = block
      end
      # 把原來(lái)的 method 存起來(lái)
      # 執(zhí)行時(shí)若是在 Overload_Dispetch_Db 裡找不到要求的 method 的話
      # 就會(huì)呼叫這個(gè)原來(lái)的這個(gè) method
      if method_defined?(method_id) && !method_defined?("old_#{method_id}")
      alias_method "old_#{method_id}", method_id
      end
      # 動(dòng)態(tài)的生成 method
      body = ""
      # 首先把 Hash 根據(jù)參數(shù)型態(tài)做排序
      # 然後一個(gè)一個(gè)的產(chǎn)生程式碼存到 body 之中
      # 這裡的排序是把有指定型態(tài)的排在前面
      dd.sort do |a,b|
      if  Array === a[0][1]
      Array === b[0][1] ? (a[0][1].length <=> b[0][1].length) : -1
      else
      Array === b[0][1] ? 1 : a[0][1] <=> b[0][1]
      end
      end.each_with_index do |((mid,spec), target), i|
      body<<<<-EOS
      #{i == 0 ? ‘if‘ : ‘elsif‘} #{OverLoad.spec_to_code(spec)}
      Overload_Dispetch_Db[[:#{mid},#{spec.inspect}]].call(*args)
      EOS
      end
      method = <<-EOS
      def #{method_id.to_s}(*args)
      #{body}
      else
      if respond_to?:old_#{method_id}
      old_#{method_id}(*args)
      else
      raise "Could not dispatch"
      end
      end
      end
      EOS
      # 先把原來(lái)的 method undefine
      # 再把做出來(lái)的 code 加到目前的 class 中
      remove_method(method_id)
      class_eval method
      end
      end
      end
      end
      

      值得注意的是,在程式中的 Overload_Dispetch_Db 不能直接使用,要用 const_get 和 const_set 來(lái)存取。這是因?yàn)樽償?shù)的 scope 的關(guān)係。在 class.eval 的 block 中,直接使用會(huì)被以為是 module OverLoad 的 Constant 而出現(xiàn)問題。

      以之前舉的例子來(lái)看,最後 Test 裡的的 t1 會(huì)是這個(gè)樣子:

      def t1(*args)
      if String === args[0] && String === args[1]
      Overload_Dispetch_Db[[:t1,[String, String]]].call(*args)
      elsif args.length == 1
      Overload_Dispetch_Db[[:t1,1]].call(*args)
      elsif args.length == 2
      Overload_Dispetch_Db[[:t1,2]].call(*args)
      else
      if respond_to?:old_t1
      old_t1(*args)
      else
      raise "Could not dispatch"
      end
      end
      end
      

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多