byterat

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            54 隨筆 :: 0 文章 :: 15 評論 :: 0 Trackbacks
          原文出處: http://www.rubychina.org/viewthread.php?tid=124&extra=page%3D1

          ? ? 元編程并不是一個很新的概念,通常元編程被認為是通過程序來生成程序,如果從這種意義上來考慮,那么lex和yacc以及JavaCC應該都可以算是具有了元編程的概念,在Java中,元編程得到了廣泛的應用。但在Ruby中,元編程的使用變得相當的簡單和容易實現,使用Ruby語言本身來產生Ruby代碼,不需要借助外部的工具,著名的RoR框架就是建立的Ruby元編程的基礎上的。可能你你對元編程還沒什么概念,但是Ruby已經內建了元編程這種機制,所以很有可能,你在不知不覺中就已經使用了Ruby元編程技術為你帶來的方便之處。如下面這段代碼:

          class Person
          ? ?attr_reader :name
          end
          你肯定知道 :name 是和 @name 相關聯的,但是你不一定清楚它到底是怎么實現的,其實attr_reader方法的實現就是采用了元編程技術,如下面的這段代碼:

          class Module
          ? ? def attr_reader(*syms)
          ? ?? ???syms.each do |sym|
          ? ?? ?? ?? ?class_eval %{def #{sym}? ?
          ? ?? ?? ?? ?? ?? ?? ?? ?? ???@#{sym}
          ? ?? ?? ?? ?? ?? ?? ?? ? end
          ? ?? ???end? ?
          ? ? end
          end

          ? ? 看了這段代碼,你應該大概了解元編程的機制了吧,如果你現在還不了解,那么我建議你先認真的學習一下Ruby的反射機制,然后再接下去看這篇帖子,因為下面介紹的內容并不是一杯嬰兒奶粉。

          ? ? 在Ruby On Rails中,有一個OR映射層,就是動態的從一張關系表映射到一個對象,這主要由ActiveRecord類來實現。在OR映射模型中,將關系數據庫中的關系表表映射到對象模型時,將關系表的表名映射到類名,表中的每一個元組映射到對應于這個類的一個對象,元組的一個字段對應于對象的一個屬性。

          假如我們有一個保存職員基本信息的文件,文件的格式是這樣的:第一行是文件內容的每個字段的名稱,從第二行開始,則是每個職員的基本信息。現在我們有一個文件名為“employee.txt”的文件,其內容如下所示:


          name,age,gender

          "John", 23, "male"

          "Linclon", 25, "male"


          假設我們就要從這個文本文件中讀取數據,并進行一定的處理。如果是使用C++編程,你首先一定會想到應該定義一個Employee類,然后這個類中有name, age, gender這些成員變量。但是是采用這種方法的話,可以發現,如果想在職員信息中加入一個字段,比如部門(department),就不得不修改Employee類的代碼,在Employee類中增加一個“department”成員變量,所以我們的代碼是高度依賴于文件的具體格式,這當然不是一個好的現象。我們希望有一種更簡單和優雅的方案,還有,Ruby動態性提高給我們一個解決方案,但是,我們應該從和下手呢,這就需要Ruby的元編程能力。


          ? ? 首先,我們想應該有一個職員類,在Rails中,每個關系表的名稱會成為類的名稱,在這里,采用類似的方法,將文本文件的名稱作為類的名稱,在Ruby中,類名同時也是一個常量名,所以第一個字母必須為大寫,我們使用如下的代碼來生成類名。


          class_name = File.basename(file_name, ".txt").capitalize
          # "employee.txt" => "Employee"
          klass = Object.const_set(class_name, Class.new)



          Class.new生成一個新的類,這個類的名稱是匿名的,所以采用const_set操作來綁定一個類名,變量klass是新類型的引用。


          生成了這個類以后,需要想這個類添加姓名,年齡和性別這些屬性,這些屬性的名稱是在文本文件的的第一行中給出的。


          data = File.new(file_name)
          header = data.gets.chomp

          data.close

          names = header.split(",")


          下面的代碼給出了如何生成這些屬性,以及初始化這些屬性值。


          klass.class_eval do
          ? ? attr_accessor *names
          ? ?? ?? ?? ?
          ? ? define_method(:initialize) do |*values|
          ? ?? ???names.each_with_index do |name, i|
          ? ?? ?? ?? ?instance_variable_set("@" + name, values )
          ? ?? ???end
          ? ? end
          ????#...? ?
          end? ?

          現在,有了一系列的訪問子(可讀和可寫),通過instance_variable_set方法,又給每個屬性做了初始化。

          變量names是在塊外部定義的,由于塊的閉合性,所以變量names在塊中也是有效的。當然,為了程序的演示,又定義的了一個to_s方法,代碼如下所示:


          ? ? define_method(:to_s) do
          ? ?? ???str = "<#{self.class}: "
          ? ?? ???names.each {|name| str << "#{name}=#{self.send(name)} "}
          ? ?? ???str + ">"
          ? ? end
          ? ? alias_method :inspect, :to_s


          ? ? 完成了這些以后,對于類的構造已經基本結束了,現在就需要真正的從文本文件中讀取數據了。從文本文件讀數據應該是一個類方法,而不是一個實例的方法,其實現代碼如下:


          ? ? def klass.read
          ? ?? ???array = []
          ? ?? ???data = File.new(self.to_s.downcase + ".txt")
          ? ?? ???data.gets #throw away header
          ? ?? ???data.each do |line|
          ? ?? ?? ?? ?line.chomp!
          ? ?? ?? ?? ?values = eval("[#{line}]")
          ? ?? ?? ?? ?array << self.new(*values)
          ? ?? ???end
          ? ?? ???data.close
          ? ?? ???return array
          ? ? end


          在這個方法中,使用字的類名來匹配相關的文件,比如將Employee類映射到“employee。txt”。

          然后,從文件中讀取職員信息,由于第一行是字段定義,所以要舍棄第一行數據。從第二行開始讀取數據,每讀取一行數據,則構造一個Employee實例。通過上面這個簡單的例子,我們可以看出元編程的功能是相當之強大的,使用元編程技術,可以構造相當簡單,優雅的解決方案。

          posted on 2006-10-24 09:52 比特鼠 閱讀(486) 評論(0)  編輯  收藏 所屬分類: Ruby on Rails
          主站蜘蛛池模板: 芦溪县| 绥江县| 育儿| 仁寿县| 伊宁市| 天水市| 湖北省| 汪清县| 澄迈县| 延庆县| 新余市| 监利县| 城口县| 晋宁县| 湄潭县| 永福县| 江陵县| 开鲁县| 松江区| 岚皋县| 韶山市| 九江县| 望都县| 乌什县| 清远市| 云和县| 温宿县| 沂源县| 巴青县| 衢州市| 万山特区| 如东县| 绵阳市| 布拖县| 房产| 衢州市| 龙口市| 万年县| 洪湖市| 沁阳市| 竹山县|