跳到主要內容

發表文章

目前顯示的是有「ruby」標籤的文章

Ruby: class << self

Ruby: class << self 我們先不管class << self是什麼意思,我們先來看看動態語言有哪些有趣的用法。 Ruby可以動態的在class裡面新增,修改一些方法。譬如: class Foo def foo return 'Hello Foo' end end f = Foo.new puts f.foo # Hello Foo class Foo def foo return 'Edit Foo' end end puts f.foo # Edit Foo 有玩過RPG Maker的人應該很熟練了,RPG Maker的模組都是這樣掛上去的,直接把模組複製到整個Script的最後面,將系統原先的方法override掉(這邊我講override其實有點問題,因為override比較適合用在編譯時期,子類別繼承並修改父類別的方法,但這裡單純只是修改類別原先的方法) 好的,那如果我產生兩個Foo物件,延續上例的類別 class Foo def foo return 'Hello Foo' end end f1 = Foo.new f2 = Foo.new puts f1.foo # Hello Foo puts f2.foo # Hello Foo class Foo def foo return 'Edit Foo' end end puts f1.foo # Edit Foo puts f2.foo # Edit Foo 因為是直接對類別做修改,所以上例中,f1與f2的行為都會改變。 那如果我們今天想要做出像Javascript那種功能,只對單一物件新增或修改方法,有辦法做到嗎?譬如Javascript可以這麼做: function Foo(){ } Foo.prototype.foo = function(){ return "Hello foo"; } var f1 = new Foo(); var f2 = new Foo(); console.log( f1.foo() ); // Hello foo console....

陣列洗牌程式(shuffle array)

陣列如何把它的順序打亂,作出類似洗牌的效果,我一直都很頭痛,搞得非常的複雜。至從用了Ruby,Array物件包含 shuffle 方法之後,我就沒思考過陣列洗牌的問題了,反正Ruby幫我處理得好好的。 Ruby # 52張牌的牌堆 poker = (1..52).to_a # => [1, 2, 3, ... , 52] # 洗牌打亂 shuffled = poker.shuffle # => [22, 32, 12, ... # 也可以直接打亂原來的陣列 poker.shuffle! # => [39, 47, 3, ... Javascript Javascript我就頭痛了,我得自己寫洗牌的方法。我在網路上找到了這個演算法,仔細看了之後,才知道原來洗牌可以這麼簡單: // 原本for迴圈是一行程式,太難理解,這邊改寫成多行 function shuffle(o){ for(var j, x, i = o.length; i;){ j = Math.floor(Math.random() * i); // javascript的array是0-base // 所以迴圈第一次進入,--i後表示陣列最後一個位置。 x = o[--i]; o[i] = o[j]; o[j] = x; // 以上三行代表以x為temp, o[i], o[j]做交換 } return o; //回傳陣列,我一開始也看錯看成回傳0 }; 變數說明 引數o: 將被洗牌的陣列 for迴圈內 i : 將會從陣列的最後一個位置,慢慢往前移到第一個位置(但移到第一個位置時for迴圈不執行,因為Javascript的數值0也代表false,會離開迴圈。0代表flase這點跟Ruby不一樣) j : 將會被亂數選擇,選到要被交換的位置 x : 用來暫存o[i]的數值,幫助o[i]與o[j]做數值交換 就這樣從最後一個位置開始,依次往前隨機挑選一個位置與它交換(可能挑到自己,表示不交換),來達到洗牌的效果,陣列多大,就執行幾次,時間複雜度 O(n) ,...

Ruby,檔案定期備份

我最近把資料庫系統換成了SQLite,直接放到RamDisk去執行。今天想要寫支程式,可以定時檢查RamDisk,裡面的sqlite檔有沒有變動,有變動就備份到硬碟去。於是使用Ruby寫下了: FILE_TO_CHECK = ARGV[0] FILE_TO_SAVE = ARGV[1] if !File.exists?(FILE_TO_SAVE) `cp #{FILE_TO_CHECK} #{FILE_TO_SAVE}` exit end check_file = File.new FILE_TO_CHECK save_file = File.new FILE_TO_SAVE if check_file.mtime > save_file.mtime `cp #{FILE_TO_CHECK} #{FILE_TO_SAVE}` end 不錯,不錯,想說這樣這隻程式可以放到crontab去,將來有同樣要檢查的檔案就編輯在crontab裡: 0 * * * * ruby /check_file.rb sinkfile sourcefile 不過做到這邊,突然想到,安裝 rsync 不就行了,直接 0 * * * * rsync sinkfile sourcefile rsync就是檢查檔案有無更動,有更動的才會複製,而且它是這麼老牌又穩定的lib了,呵呵,沒關係,就當做是在練習使用vim編輯器

Ruby,Time.new(自定時間格式)

Ruby 製作Time物件時,必須遵守一定的格式,譬如 Time.new(2014, 2, 13, 16, 30, 30, "+08:00") #=> 2014-02-13 16:30:30 +0800 Time.new 裡頭接受的參數從年,月,日,時,分,秒,時區,沒填的就預設是0,全部都沒填,那就給系統當前時間。那問題如果我們得到的時間是一個字串呢?例如我們有一個時間字串: 2014-02-13 16:50:47 +0800 這串文字當參數傳到到 Time.new 裡面只會出現錯誤訊息,難道要開始做苦工先字串解析,在放到 Time.new 裡面嗎? Time.strptime 用到字串解析也就太辛苦了,Ruby 的Time class提供一個strptime方法,可以直接定義time format, require 'time' 之後就可以使用了直接舉個例子: require 'time' t = Time.strptime("2014-02-13 16:50:47 +0800", "%Y-%m-%d %H:%M:%S %z") # => 2014-02-13 16:50:47 +0800 t.class # => Time 就直接得到了Time物件了,省去了字串解析的麻煩。 如果你需要的 DateTime 物件,也可以依法炮製: require 'time' dt = DateTime.strptime("2014-02-13 16:50:47 +0800", "%Y-%m-%d %H:%M:%S %z") # => #<DateTime: 2014-02-13T16:50:47+08:00 ((2456702j,31847s,0n),+28800s,2299161j)> dt.class # => DateTime 一樣可以直接得到 DateTime 物件。 如此就可以從各式各樣的時間格式,直接產生 Time 與 DateTime 物件了。來試個怪怪的格式: time = Time.strptime("22日2008年06月...

以Ruby語言執行系統命令

以Ruby語言去執行系統命令,有下列三種方式 exec args system args %x( args ) 或 ` args ` exec args exec 會中斷目前Ruby正在進行的process,然後執行系統命令。所以這個指令還蠻少用的,可以在irb裡面試試 root$ irb 2.1.0 :001 > exec 'pwd' /Users/wemee/Documents/GitHub/test root$ irb直接被中斷掉,然後進入bash執行pwd,所以大概只能用在linux的crontab裡面,定期執行一次就中斷 system args system 則會保留目前Ruby的process,執行完系統命令後,依照執行結果回傳: true: 執行成功 false: 執行失敗,譬如移動不存在的檔案 * nil: 執行的指令本身就打錯 system 'pwd' # => true system 'mv not_exist_file.txt foo.txt' # => false system 'wrong instruction' # => nil %x( args ) 或 ` args ` 這兩個也都不會重斷Ruby的process,並且執行完後,完整回傳系統命令回傳的字串。%x( args ) 或 ` args `兩種寫法執行結果都一樣,所以我都寫` args `,而且 ruby-style-guide 也多半認為少用%x比較好。 dir = `pwd` # => dir = "/Users/root/projects\n" files = `ls` # => files = "main.rb\ntemp.txt\ntest.txt\n" 這邊可以接著用 string.chmop 把最後面字尾那個"\n"刪掉,或用用 string.gsub("\n", " ") 把所有的"\n"替換成空白欄位。 最後,執行這些指令之前,記得檢查一下你的系統唷,很多linux的指令,跟win...

Ruby 併行賦值(Parallel Assignment)

前言 原本在找Ruby要怎麼交換兩個陣列的位置,找到一個很神奇的方法 class Array def swap!(a,b) self[a], self[b] = self[b], self[a] self end end 完全看不懂在幹嘛,如果是C語言,在同一行裡使用逗號,則表示從右到左依次執行而已,例如: int i,j; for(i=0,j=5;i<10;i++,j--); 在C語言這個迴圈共執行10次,每次都執行i++與j--,我把i++與j--寫在一起用逗號分開,其實也可以這麼寫 int i,j; for(i=0,j=5;i<10;){ i++; j--; } 有時候為了簡潔會塞在同一行。 可是Ruby這麼做,我全看不懂在幹嘛,在文章開頭的swap!函式裡頭,self[a]在我眼裡就是回傳self[a],然後將self[b]賦值self[b]等於沒變,最後再回傳self[a]而已,完全不清楚這是怎麼swap。 Parallel Assignment 查了一下 ruby-doc.com 之後,找到了 Parallel Assignment 這個關鍵字,終於搞清楚了,Ruby會將等號右邊所有的物件,按照相對位置賦值到等號左邊的參數,就叫做 Parallel Assignment ,譬如你要將x,y,z分別賦值1,2,3,在C語言你可能這麼寫 int x=1, y=2, z=3; 在Ruby裡面可以這麼寫 x,y,z = 1,2,3 就是如此而已,x,y,z就分別被賦值1,2,3。 當然,像我這種宅宅,一定還會好好地玩弄一下,我故意讓等號兩邊無法成對: 1: a,b = 1,2,3 # a=1, b=2 2: i,j,k = 1,2 # i=1, j=2, k=nil 行1,我原本以為b會被賦值為陣列[2,3],其實不用這麼古怪,Ruby設計直接把多出來的3丟掉,聰明的設計。 行2,我原本以為會出現錯誤訊息,但這也太嚴謹了,Ruby直接讓k=nil就行了,也是聰明的設計。 接著繼續惡搞一下,看他的語法有沒有靈活性: a,b = c=1, 2 # a=1, b=2, c=1 a,b = c,d = 1, 2, 3 ...

Markdown to HTML(Maruku)

Maruku on Github 本文網址 純Ruby做成,可將Markdown語法轉換成HTML,latex,md...等格式,以下簡單做點介紹。 安裝 gem install maruku 先在irb下面做點測試 require 'Maruku' # => true # 設定Markdown字串 markdown_string = '#大標題' # 使用Markdown字串 建立Maruku物件 doc = Maruku.new(markdown_string) #從Maruku物件輸出HTML文檔 doc.to_html # => "\n<h1 id=\"\">大標題</h1>\n" #從Maruku物件輸出latext文檔 doc.to_latext_document # => "\\documentclass{article}\n\n% ... 至於還有哪些Methods 自己用Ruby內建的methods語法來顯示 Maruku.methods # => 一堆class methods Maruku.new.methods # => 一堆instance methods 可以再加上正規表示式來尋找 Maruku.new.methods.grep(/html/) # => 一堆HTML相關的instance methods Maruku.new.methods.grep(/latex/) # => 一堆latex相關的instance methods 與Ruby on Rails結合 在Gemfile裡面加上 gem 'maruku' 譬如你自己做個Blog,讓人使用Markdown語法來寫文章。文件從資料庫取出來,直接傳給view顯示就行了,例如文章儲存在Post資料表的content欄位 Markdown_string = Post.first.content @doc = Maruku.new(Markdown_string) 在view...