自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從實戰(zhàn)項目總結(jié)的Ruby小技巧(第一部分)

開發(fā) 后端 前端
從我們在Global Personals項目中使用Github并且following Github Flow開始到現(xiàn)在已經(jīng)將近兩年的時間。在這段時間中,我們以很高的頻率提交了上千次的pull請求,雖然沒有太多如何改善或提高程序的建議和想法,但是 我仍獲得了如此廣泛和珍貴的經(jīng)驗。其中,有一些建議是和項目相關(guān)的,同時,也包含了大量可以在團(tuán)隊內(nèi)分享的Ruby開發(fā)小技巧。

從我們在Global Personals項目中使用Github并且following Github Flow開始到現(xiàn)在已經(jīng)將近兩年的時間。在這段時間中,我們以很高的頻率提交了上千次的pull請求,雖然沒有太多如何改善或提高程序的建議和想法,但是 我仍獲得了如此廣泛和珍貴的經(jīng)驗。其中,有一些建議是和項目相關(guān)的,同時,也包含了大量可以在團(tuán)隊內(nèi)分享的Ruby開發(fā)小技巧。

由于我擔(dān)心將從這個項目中獲得和學(xué)習(xí)到的如此珍貴的技巧和經(jīng)驗所遺忘,于是我挑出了其中***的最有價值的部分和大家分享,同時進(jìn)行了一點小小的擴 展。每個人都有自己的工作方式和風(fēng)格,所以我會簡潔明了地和大家闡述。并不是每部分內(nèi)容對每個人來說都是新的,但是希望你在這里可以或多或少都有所收獲。

我將文章分為了幾塊內(nèi)容,以免你一口氣讀完5000個字,同時將它們歸類為幾個部分以便于參考。

  1. 代碼塊(Blocks) 和 區(qū)間(Ranges)
  2.  重構(gòu)(Destructuring) 和 轉(zhuǎn)換方法(onversion Methods)
  3.  異常(Exceptions)和模塊(Modules)
  4. 調(diào)試(Debugging),項目結(jié)構(gòu)(Project Layout)和文檔(Documentation)
  5.  其他(Odds and Ends)

讓我們進(jìn)入***部分。

代碼塊(Blocks)

代碼塊是Ruby非常重要的一部分,你隨處都見到它們被廣泛使用。如果你沒有使用,那么你將發(fā)現(xiàn)許多人使用方法關(guān)聯(lián)代碼塊,甚至僅僅是讓代碼結(jié)構(gòu)變得清晰而已。

代碼塊有三種主要的作用:循環(huán)(looping),初始化和銷毀(setup and teardown),以及回調(diào)和延遲執(zhí)行(callbacks or deferred action)。

下面這個例子演示了如何使用代碼塊循環(huán)輸出菲波那切數(shù)列。它使用block_given?方法判斷是否關(guān)聯(lián)了一個代碼塊,否則將從當(dāng)前方法返回一個枚舉器。

yield關(guān)鍵字用來在方法中執(zhí)行一個代碼塊,它的參數(shù)將傳遞給代碼塊。當(dāng)代碼塊執(zhí)行完畢,將返回調(diào)用方法,并執(zhí)行下一行代碼。方法返回值為在***數(shù)(max)之前的***一個菲波那切數(shù)。

  1. def fibonacci(max=Float::INFINITY) 
  2.       return to_enum(__method__, max) unless block_given? 
  3.       yield previous = 0 
  4.       while (i ||= 1) < max 
  5.         yield i 
  6.         i, previous = previous + i, i 
  7.       end 
  8.       previous 
  9.     end 
  10.   
  11.     fibonacci(100) {|i| puts i } 

下一個例子將把設(shè)置、銷毀以及錯誤處理等操作代碼放到方法中,將方法的主要邏輯放到代碼塊中。通過這種方式,樣板代碼就不需要在多個地方重復(fù),另外當(dāng)你需要改變錯誤處理代碼時,只需要做少量的修改。

yield語句的返回結(jié)果,即代碼塊的返回值,將保存到一個局部變量中。這樣,可以將代碼塊的執(zhí)行結(jié)果作為方法的返回值。

  1. require "socket" 
  2.   
  3.     module SocketClient 
  4.       def self.connect(host, port) 
  5.         sock = TCPSocket.new(host, port) 
  6.         begin 
  7.           result = yield sock 
  8.         ensure 
  9.           sock.close 
  10.         end 
  11.         result 
  12.       rescue Errno::ECONNREFUSED 
  13.       end 
  14.     end 
  15.   
  16.     # connect to echo server, see next example 
  17.     SocketClient.connect("localhost", 55555) do |sock| 
  18.       sock.write("hello"
  19.       puts sock.readline 
  20.     end 

下一個例子不會使用yield關(guān)鍵字。這里有另外一種使用代碼塊的方法:將‘&’作為方法***一個參數(shù)的前綴,將把關(guān)聯(lián)代碼塊作為一個Proc對 象保存到此參數(shù)當(dāng)中。Proc對象擁有一個call實例方法,可以用來執(zhí)行代碼塊,傳遞給call方法的參數(shù)將作為代碼塊的參數(shù)。在這個例子中,你可以保 存代碼塊最為一個回調(diào)稍后執(zhí)行,或者在你需要的時候執(zhí)行延遲的操作。

  1. require "socket" 
  2.   
  3.     class SimpleServer 
  4.       def initialize(port, host="0.0.0.0"
  5.         @port@host = port, host 
  6.       end 
  7.   
  8.       def on_connection(&block) 
  9.         @connection_handler = block 
  10.       end 
  11.   
  12.       def start 
  13.         tcp_server = TCPServer.new(@host@port
  14.         while connection = tcp_server.accept 
  15.           @connection_handler.call(connection) 
  16.         end 
  17.       end 
  18.     end 
  19.   
  20.     server = SimpleServer.new(5555) 
  21.     server.on_connection do |socket| 
  22.       socket.write(socket.readline) 
  23.       socket.close 
  24.     end 
  25.     server.start 

區(qū)間(Ranges)

區(qū)間在Ruby代碼中也很常見,通常區(qū)間的形式是(0..9),包含0到9之間的所有數(shù)字,包括9。也有另一種形式(0…10),包含0到10之間的所有數(shù)字,不包括10,即和前一種形式都包含0到9之間的所有數(shù)字,包括9。這種形式并不常見,但有時卻非常有用。

有時候你會看到像這樣的代碼:

  1. random_index = rand(0..array.length-1) 

使用不包含結(jié)尾的區(qū)間將更加整潔:

  1. random_index = rand(0...array.length) 

#p#

有時候,使用不包含結(jié)尾的區(qū)間將更加簡潔和直觀。例如,eb_first…march_first可以更加簡單的計算出今年二月的天數(shù),同時,1…Float::INFINITY可以更加直觀的表示出所有正整數(shù),由于無窮大infinity不是一個數(shù)字。

區(qū)間是優(yōu)秀的數(shù)據(jù)結(jié)構(gòu),因為它允許你定義一個巨大的集合而不需要在內(nèi)存中實實在在的創(chuàng)造出整個集合。你必須小心你所使用的方法,因為某些區(qū)間操作可能導(dǎo)致整個集合被創(chuàng)建。

實例方法each顯而易見會創(chuàng)造出整個區(qū)間,但這通常只會發(fā)生在每次使用***個對象的時候,例如 (1..Float::INFINITY).each {|i| puts i },在沒有輸出任何信息之前,事實上不可能用盡所有可用內(nèi)存。區(qū)間對象中,mixin Enumerable所獲得的方法依賴于each方法,所以它們也具有相同的行為。

區(qū)間有include?和cover?兩個實例方法來測試一個值是否屬于區(qū)間。include?方法使用each方法迭代整個區(qū)間來檢測值是否存在 于區(qū)間中,cover?方法只是簡單比較值是否大于區(qū)間的開頭,并且小于等于區(qū)間的結(jié)尾(對于不包含結(jié)尾元素的區(qū)間是小于區(qū)間的結(jié)尾)。這兩個方法是不可 以等價互換的,可能由于區(qū)間建立方式的不同和排序方式的不同,而導(dǎo)致意象不到的結(jié)果。

  1. ("a".."z").include?("ab")     # => false 
  2. ("a".."z").cover?("ab")       # => true 

Ruby中許多類都可以進(jìn)行區(qū)間操作,同樣的,你也可以很容易地讓自定義的類進(jìn)行區(qū)間操作。

首先,你需要在類中實現(xiàn)稱之為‘太空船’<=>操作符的方法。在這個方法中,如果other參數(shù)大于self返回-1,如果小于返回1,如果相等則返回0。一般情況下,如果比較是不合法的則返回nil。

下面的例子中,簡單的代理了String#casecmp方法,這個實例方式是一個大小寫不敏感的字符串比較方法,返回上面敘述的格式。

  1. class Word 
  2.      def initialize(string) 
  3.        @string = string 
  4.      end 
  5.   
  6.      def <=>(other) 
  7.        return nil unless other.is_a?(self.class
  8.        @string.casecmp(other.to_s) 
  9.      end 
  10.   
  11.      def to_s 
  12.        @string 
  13.      end 
  14.    end 

這樣的話,你便可以創(chuàng)建一個區(qū)間,通過實例方法cover?測試成員關(guān)系,但這通常不是一種非常好的做法。

  1. dictionary = (Word.new("aardvark)..Word.new("xylophone") 
  2. dictionary.cover?(Word.new("derp"))   # => true 

如果你想要迭代整個區(qū)間,生成一個數(shù)組,或者是使用實例方法include?測試成員關(guān)系,你需要實現(xiàn)succ方法,這個方法產(chǎn)生序列中的下一個對象。

  1. class Word 
  2.      DICTIONARY = File.read("/usr/share/dict/words").each_line.map(&:chomp
  3.      DICTIONARY_INDEX = (0...DICTIONARY.length) 
  4.      include Comparable 
  5.   
  6.      def initialize(string, i=nil
  7.        @string@index = string, i 
  8.      end 
  9.   
  10.      def <=>(other) 
  11.        return nil unless other.is_a?(self.class
  12.        @string.casecmp(other.to_s) 
  13.      end 
  14.   
  15.      def succ 
  16.        i = index + 1 
  17.        string = DICTIONARY[i] 
  18.        self.class.new(string, i) if string 
  19.      end 
  20.   
  21.      def to_s 
  22.        @string 
  23.      end 
  24.   
  25.      private 
  26.   
  27.      def index 
  28.        return @index if @index 
  29.        if DICTIONARY_INDEX.respond_to?(:bsearch# ruby >= 2.0.0 
  30.          @index = DICTIONARY_INDEX.bsearch {|i| @string.casecmp(DICTIONARY[i])} 
  31.        else 
  32.          @index = DICTIONARY.index(@string
  33.        end 
  34.      end 
  35.    end 

你會注意到我同時也mixin了Comparable模塊,這樣在定義了實例方法<=>之后,類也擁有了實例方法==(同時也擁有了實例方法>,<等),而不是繼承自O(shè)bject類。

現(xiàn)在我們的區(qū)間將變得更加強大

  1. dictionary = (Word.new("aardvark")..Word.new("xylophone")) 
  2.   dictionary.include?(Word.new("derp"))                  #=> false 
  3.   
  4.   (Word.new("town")..Word.new("townfolk")).map(&:to_s)   #=> ["town", "towned", "townee", "towner", "townet", "townfaring", "townfolk"] 

下一部分內(nèi)容將會很快和大家見面,在Twitter上follow我們將會即時收到***的消息……

原文鏈接:http://globaldev.co.uk/2013/09/ruby-tips-part-1/

譯文鏈接:http://blog.jobbole.com/48413/

責(zé)任編輯:陳四芳 來源: 博樂在線
相關(guān)推薦

2009-06-11 15:25:39

Java隨機數(shù)

2019-04-10 11:06:54

前端HTMLCSS

2009-06-09 14:40:01

Javascript表單驗證

2009-06-12 10:34:40

Java Date

2009-06-12 10:08:05

StaticJava

2025-04-24 00:10:00

RAGAI人工智能

2025-01-22 08:01:53

2013-07-08 15:45:04

Python

2013-04-08 15:42:38

Backbone.js入門

2018-11-15 14:52:15

Spark數(shù)據(jù)機器學(xué)習(xí)

2011-08-03 10:12:38

2009-06-15 13:32:18

Java applet插件

2020-10-10 14:36:10

Python

2013-11-14 16:18:05

AndroidAudioAudioTrack

2018-12-19 09:03:04

物聯(lián)網(wǎng)供應(yīng)鏈物聯(lián)網(wǎng)應(yīng)用

2009-07-14 13:49:28

Swing組件AWT

2020-10-12 00:41:52

Python變量

2024-05-15 08:12:11

SignalJavaScriptPromises

2010-03-11 11:29:51

喬布斯

2020-10-13 09:54:38

內(nèi)存技術(shù)數(shù)據(jù)
點贊
收藏

51CTO技術(shù)棧公眾號