[閒聊] Magic RoR

真的是很奇怪,雖然心裡有千百個不願意,但是每當想到要「架站」這個動作的時候,腦海第一個閃過去的東西不是PHP反而是RoR,每次一想到它的scaffold還有人性化的generator,就有種讓要用它的衝動。

原來Ijs當初的那番話…我還太淺了XD,還有很多東西要和她學呢。

[Ruby] 8th word

不知道自己還會持續寫多久,雖然自己內心有千百個不願意學Ruby(就是單純不想而已,那個Fu不對),不過我還是會繼續加油的。就當作翻譯書吧XD…

現在要再延續上次講的equality。如果還有點印象的話,應該是談到「==」operator吧,既然有正就有反,當然有「!= (Not equal)」啦,書上說,只要原先的「==」operator有被定義的話,那麼這個operator就是把它的值做invert的動作,true←→false那個值互換,所以這在Ruby1.9之前,Ruby會自動把這個operator給你使用for free!!(前提是你有定義好其「==」的動作),而在Ruby1.9之後,類別可以自己定義自己的「!=」operator來達到自己想要的效果。

有時候很該死的就是會出現很多相似的Method,這真的是很煩,因為要了解他們之間那極度細微的差異,不過也不能怪誰,因為那是別人規範好的= =…

3.8.5.3 The eql? method

「eql?」是一個不做type conversion的Method,來看一下他和「==」的差別:

http://gist.github.com/293535.js?file=gistfile1.rb

原來如此呀,恩恩…

3.8.5.5 The =~ operator

這就酷了,看到這個就想起RE的日子,YES,這就是用在做Pattern matching的operator,被定義在String和Regexp的類別下,不過書上也說了這其實和equality沒有什麼太大的關係,只不是有個「=」就把它放在這邊XD,所以只要記得這是拿來做Regular Expression用的就好了,來個小例子,其他深入的後面再談:

http://gist.github.com/293540.js?file=gistfile1.rb

3.8.6 Object Order

這邊有一個好玩的東西叫做物件的排序,哇靠這是啥?我原本也不知道它想幹嘛,不過看一下書後就了解許多了。通常每個類別都會定義「==」來了解equality,而有些類別,還會定義「排序」。什麼意思咧,假設有BC兩個都是A類別的實體,我們可以定義說它那兩個實體是「相等」,還是B比C小。原本我看到這都傻眼了,這是什麼鳥,完全看不懂呀,但是它下面提到了「Number」這個類別就是一個很明顯的例子,整個一下子就通了!!!

怎麼說呢?因為萬物皆OO的Ruby,其實「數字(123)」個別都是一個物件呀,而我們的數字可以比大小,就代表在某些類別下是可以比大小的,因此在某一方面來說就是做了一個排序的動作,這樣子是不是就很好了解了!?

所以如果我們要在Ruby做「排序」這件事情的話,就要使用「」這個operator。「AB」代表說,如果AB就會回傳1。來看個例子:

http://gist.github.com/293542.js?file=gistfile1.rb

但是因為這個Operator不太直覺,所以類別都會再include「Comparable」模組來做混入(mixin),而它定義了這幾個operator如下:

http://gist.github.com/293543.js?file=gistfile1.rb

下面這個是我在說明內找到的一個還蠻容易看懂的範例,可以參考一下他是怎麼做到的:

http://gist.github.com/293545.js?file=gistfile1.rb

另外有一點雖然前面提過了,但是還是要注意一下,那就是Comparable模組沒有定義「!=」,不過Ruby會自動幫我們先做「==」的動作再把結果Invert,所以就免擔心啦。

最後要是書上提到的一個NaN的情況(0/0的時候),而比較的結果就請看一下Code啦:

http://gist.github.com/293547.js?file=gistfile1.rb

這邊來了一個問題,為什麼「nan.euqal?(nan)」的結果是True??沒錯,因為他們兩個都是指向同一個object,所以結果為真,這邊要注意一下!!

BTW,通常「==」會被覆寫掉,但是「Aobj.equal?(Bobj)」是不應該在子類別被覆寫的,這是說明上面特別強調的一點,還要再注意一下!!

就是這樣,這篇就先到這啦,我要來去玩了XD~

[Ruby] 7th place

3.8.4 Object Class and Object Type

在這一大堆的Object下,要找到其所屬的類別還真的是有點麻煩,特別是我們又不知道有哪些類別的時候= =,所以還好萬物階OO的Ruby有提供了幾個Method來用,如果先前有留心例子的話應該都有看過了,不過沒關係,再看一下吧:

http://gist.github.com/292409.js?file=gistfile1.rb

酷哦,有看到的就賺到了,因為這邊除了Object#class這個Method外,還提到了Class#superclass這個Method,可以用串接的方式一直串下去,找到階層架構下最項層的Class直到nil。

但是在Ruby1.9下就有點不一樣了,Object在階層架構下不再是Root的角色(如上例):

http://gist.github.com/292412.js?file=gistfile1.rb

True,Object上面還有一個叫做BasicObject的parent class,再上去才是nil,這和Ruby1.8有點不一樣,可能要注意一下。這在後面的7.3還會有更詳細的說明,就先丟者吧XD

所以要判斷一個Object的類別就可以這樣做啦:

http://gist.github.com/292414.js?file=gistfile1.rb

當然也還有另一個選擇:

http://gist.github.com/292418.js?file=gistfile1.rb

當然,如果要再進階一點,你還可以這樣玩:

http://gist.github.com/292422.js?file=gistfile1.rb

大概了解了一下那些函式的玩法,這邊又提到一個「===」運算子可以代替「is_a?」這個Method,所以上面有用到該Method的都可以改成「===」來玩,在這邊有說到,不要了解該Object的類別,我們只要知道有哪些Method可以用就好了(暫時),要不然我們應該會陷入鬼影追追追的Loop吧XD。

另外如果我們想要知道該Object有沒有那個Method的話,可以這樣子測試:

http://gist.github.com/292427.js?file=gistfile1.rb

3.8.5 Object Equality

講完了一堆霧沙沙的Method,也只有等哪天真的要測試的時候會比較有用,不過就先記下來自己研究吧XD(懶人),在這邊要來討論一下比較Object的一些相同性。

3.8.5.1 The equal? method

這個「equal?」的Method是被定義在Object這個類別下,用來測試兩個值是不是參考到同一個Object用的,對於兩個不同的Object的話,就會回傳False,來看VCR:

http://gist.github.com/292433.js?file=gistfile1.rb

OH,MY,這個真是個經典的例子,如果在前面幾章的地方,我們有討論到字面上去宣告一個Object會產生的情形,就是每一個值都會參考到不同的Object,而這邊就是再次使用了這個例子來做說明,讓我們知道雖然兩個Object都叫做「Ruby」,但是其實是代表不同的「Ruby」,所以B、C都參考到了同一個「Ruby」,而A則參考到了另外一個,也就是為什麼一個euqal?的結果為False,另一個卻是True的原因了。

不過我們也可以用「==」來做到相同的事,只要A.object_id == b.object_id就可以啦,因為先前提到的,每個Object都會被授與一個Unique的Object Id,不知道大家還記不記得XD,還好我還沒忘記咧,差點就要被你們唬爛過去了QQ。

好啦,先玩到這邊,晚點再來寫別的內容,大家快去吃東西吧XD。

[Ruby] 6th object

終於來到了Ruby的重點了,即「萬物皆物件」的重點章節-「物件(Object)」!

3.8 Objects

在書中,直接使用了高中老師教我的破題法,一開始就來個下馬威說「Ruby是個非常物件導向的語言,所有的值都是物件」,而且提到了一個很重要的概念,它說「所有的物件都是先繼承『Object』這個類別」,所以它的Method都可以直接被使用,真是重要的一點!!

在這章就介紹一些基本的資訊,雖然不多,卻是打基礎重要章節!!

3.8.1 Object References

在Ruby下,當我們在使用物件的時候,我們是在使用它的「參考(References)」,並不是直接使用物件本身。舉例來說,當我們Assign一個值給一個變數的時候,我們不是把整個物件複製過去,反而只儲存一個「物件的參考」而已,就像是C語言內的Pointer的一樣。

耶,Live Demo:
http://gist.github.com/291478.js?file=gistfile1.rb

例子都直接先中文化了,應該還蠻清楚的,反正只要記得「物件參考」這個特性就好了,因為這也是這節最重要的概念。

所以我們在執Method的時候,就是利用Pass By Value(傳值)的方式把該物件的Reference當作一個參數傳進去,並不是該物件本身,因為Method就能透過該Reference來直接對整個Object做改變,就不需要把「整個物件」傳進去了,真是一個輕便的作法呀。

3.8.1.1 Immediate values

在上面說到萬物階物件的概念,不過這邊有了一個例外(人生就是很多例外XD?)那就是 Immediate values = 立即值。哇靠,這是什麼,在書上的解釋是說,該類的物件(如Fixnum和Symbol)在Assign或是傳遞時把整個物件都給它丟過去,而不是像上一小節說的reference。說實在的,我還是不知道它到底是想要幹嘛,不過最後面有提到「Immediate values」和「Reference」的主要差異是在前者不能有「Singleton Method」,XX的,這是雪球效應嗎,怎麼一個問題又產生了好多個問題,好在在CH.6的時候會說到這個很怪的Method,先放著等到那個時候再來討論,現在只要知道一下有這個東西就好,等到要用到時再來詳細討論一下(逃)

3.8.2 Object Lifetime

在這邊說到,要宣告一個Object的話,如果不以「字面上(literally)」的方式,可以用new這個Method,來看一下例子:

http://gist.github.com/291501.js?file=gistfile1.rb

new是Class類別下的一個Method,它會產生一個區塊的記憶體空間來存放新的物件,然後會呼叫一個初始化的函式(initialize),並把傳給new Method的參數直接傳給它。媽呀,這怎麼有點複雜XD,應該是等後面要自己做自己的Class時才會用到這邊的東西,還是先丟著吧XD,要不然講一堆也不知道在幹嘛,我要例子啦!

3.8.3 Object Identity

每個物件都有一個識別用的identifier,像是在Fixnum下就有一個object_id的Method,會回傳一個獨特的物件id做為辨識。但是書上有提到在Ruby1.8這個Method會產生一個Warning,而在Ruby1.9也已經不採用這個Method了,但是可以改用__id__這個Method來做到相同的事情,不過經過我的測試,在Ruby1.8沒有Warning,在Ruby1.9 object_id也沒有被剔除,好像和書上說的有點不太一樣!?

前面還有些東西我晚點找到些資料再來修改一下。先準備來去吃東西XD

[Ruby] 5th street

因為CH.3後面在討論編碼的問題,不過暫時對我來說可能還用不到,不過時間有限,就來到了下一段。

3.3 Arrays

Ruby的Array類別提供了一些有趣的Method,常用的如size(同length),可以用直接回傳Array的長度。基本的東西大概都和別的語言一樣,唯一一個要注意的就是它對Out-of-bound的處理是回傳一nil,但通常別人都是直接Error了,所以可以為這種狀況做一些判斷,真是貼心呀。

來看一下Array要怎麼用:
http://gist.github.com/291064.js?file=gistfile1.rb

再上語法甜點:
http://gist.github.com/291066.js?file=gistfile1.rb

看完例子大概就很清楚要怎麼操作它了XD,而index的操作就請看前面幾篇,概念是一樣的,所以應該很好上手。

當然也要提幾個好用的東西,像是可以用「+」把兩個Array給串接起來,反之也可以用「-」把Array相符合的元素給刪除掉,來看個實際的Demo:

http://gist.github.com/291110.js?file=gistfile1.rb

水哦,還記得之前String的「<<」運算子嗎,你應該會想說,該不會在Array也可以用吧,沒錯,還真的可以用,來看看運行的情況:

http://gist.github.com/291113.js?file=gistfile1.rb

和String好像,了解一個就會這個了XD

這邊有個很有趣的就是,它也把布林運算子「&」、「|」都拿來玩了,它們是用來比較兩個Array間元素的狀況用的,廢話不多說,再來個例子:

http://gist.github.com/291115.js?file=gistfile1.rb

簡單來說,「|」就是「聯集」,而「&」就是「交集」。交集就是找出A、B兩個集合間共有的元素,而聯集就是找出A、B兩個集合的所有元素。但是在Ruby內還多了一個限制,這兩個布林運算所回傳的的結果並不會有重覆的情況(不會有[1,1 …] 這種情形)。最後,也是要特別注意的,就是Array下的這種布林運算並沒有Transitive(遞移性),即「A|B」≠「B|A」,看例子就發現其順序會相反,這要留意一下呀!!

看了這麼多例子,先來去試試看比較實在啦,文末附上Array可用的Method:

http://gist.github.com/291120.js?file=gistfile1.rb

我們下篇見XD~

[Ruby] 4th road

3.2.4 Accessing Characters and Substrings

耶,講到有趣的String了,這邊在書上有提到Ruby1.8和Ruby1.9對於String處理上面的小差異, 如果我們要存取String的子字串的話,就用「square-bracket array- index operator []吧」。其實大家應該都在別的語言上用的很習慣了,所以通常看一下Ruby對下面兩個不同版本的解釋就可以啦:
http://gist.github.com/290553.js?file=gistfile1.rb

最大的差異就是對於「單一字元」的解讀,在1.8時會回傳其ASCII碼,而在1.9時會回傳該字元(雖然我是這樣說,不過它們是各自屬於不同的Class下,在1.8,單一字元被視為Fixnum,而在1.9則被視為String,大家可以自己試試看)。

不知道之前說的單一字元的呈現如果不想用String來做的好方法還有沒有人記得?恩,就是用「?」,來看一下例子:
http://gist.github.com/290558.js?file=gistfile1.rb

上面都是如何對字串的「單一字元」做修改的例子,接下來要討論子字串了,老樣子,看例子學比較快:
http://gist.github.com/290559.js?file=gistfile1.rb

在Ruby下提供了[X,Y]的方法來讓我們存取「從第X個字元(可為負),向後抓Y長度個字元」,只是要特別小心Out-of-boundary 的問題。如果X為負則「反向從倒數第|X|個字元向後抓Y長度個字元」,很簡單吧!!?不過還有一個要注意的就是Ruby可以很彈性的依個人意識插入或是刪除字元,只要你的起始位置和長度寫好就可以了!再來個小例子吧XD
http://gist.github.com/290594.js?file=gistfile1.rb

如果你的長度Y是寫0的話,就會產生插入的效果而得到結果「HeLllo」,書上有寫出個小規則,來看一下:

If the righthand side is the empty string, this is a deletion, and if the lefthand side has zero-length, this is an insertion

所以如果右邊是Assign一個空字串,就會被視為刪除,反之如果左邊是以Y長度為0來表示的話,就視為插入!

這邊還有一個很好用的Range Object,不過因為在後面的章節會解釋的比較詳細,所以先放到後面再來說吧XD~

最後一個要講的就是我們也能利用字串來當作字串的index,如果是這樣子做的話,其回傳的值就是第一個相符合的子字串或是Nil(即Null)當沒有相符合的子字串的時候。

所以其實這個東西目前可能對我們還沒有什麼很特別的功用,不過書上也有講到,這個作法只有在當我們要取代一些子字串時會比較好用,老樣子,範例小姐請上菜:

http://gist.github.com/290625.js?file=gistfile1.rb

下面那個例子是我拿測試為什麼它while的運行狀況,結果很驚人的發現,index只印出了01也就代表說,它很精確的在一開始就找s[“l”]的位置,而不是像我預想的會以Sequential的方式來對整個String做尋找,不知道有沒有人很了解它內部真正在運作的情況是怎麼樣呢??(BTW,我的Ruby版本是1.8.6)

最後也可以用正規表達式 如 「 s[/[aeiou]/] = ‘*’ 」來做Search & Replace的動作,真是驚人!!

這節就先說到這啦,休息去XD~

[Ruby] 3rd Game

3.2.1.6 Backtick command execution

哦耶,要來講Backtick了,就是「`」這個符號,這在很多語言上面都是用來執行外部指令,這個指令真的是很方便,特別是要呼叫一些系統指令來做事的話,這個東西就一定可以幫上很多忙。

來個書上的例子:
http://gist.github.com/289810.js?file=gistfile1.rb

在這我們就可以自己去控制windows這個變數,如果是True的話就代表是在W$下執行這段程式,所以listcmd就要選擇dir,反之則用ls,真是幾行Code就把他用到出神入化XD!!而如果要在String內解析變數的話,就要用#{變數名稱}的方法,這個可能之後會很常用。

3.2.1.7 String literals and mutability

先來段原文:

Each time Ruby encounters a string literal, it creates a new object. If
you include a literal within the body of a loop, Ruby will create a new object for each
iteration.

大意是說,如果是用「字面」的方式去操作一個String的物件的話,在Ruby下會被視為不用的物件,請看下面的例子:
http://gist.github.com/289823.js?file=gistfile1.rb

恩哼,還蠻清楚的吧,我們利用times這個Method來做個實驗,發現他們各自是不同的物件,但是直覺上可能會認為是同一個,所以要避免這種做法。

3.2.1.8 The String.new method

所以我們可以用new這個method去產生個別的物件… 結束了。

其實怎麼用還是看人啦,OO玩到走火入魔的人大概會用String.new(“test”)吧,但是如果是像我這種懶人,只要避免Loop的情況,其他的就讓直譯器幫我判斷吧XD。

3.2.2 Character Literals

哦耶,一直用String真的有點煩,如果只是想要表示一個字元也來個Sring這樣不會太超過嗎??有點殺雞用屠龍刀的感覺,所以在Ruby又貼心的提供了一個方便的小東西叫「字元字面」(好鳥的名字,記英文就好啦)
http://gist.github.com/289852.js?file=gistfile1.rb
我查了一下,這類的變數是屬於「Fixnum」這個類別下的,所以它是以數字的方式來儲存這類的變數(見上例)。

3.2.3 String Operators

在String Class內提供了兩種method,一個叫「<<」、一個叫「+」,來看一下官方的解釋:

1st 「<<」
Append—Concatenates the given object to _str_

2nd「+」
Concatenation—Returns a new +String+ containing _other_str_ concatenated to _str_.

看完了解釋,可以了解到它們都是做了串接的效果,可以把兩個String的物件串接在一起,只是不同的用法而已,來看下面的例子了解一下:
http://gist.github.com/289869.js?file=gistfile1.rb
很簡單吧XD~我這個白痴都看的懂了。

先寫到這,其他的再慢慢更新。

[Ruby] 2nd round

之前忘了說明一下變數型態,下面是一個我提供的例子:
http://gist.github.com/289506.js?file=gistfile1.rb
可以知道Ruby是一種Dynamically Typed Language(和PHP一樣XD),所以在例中,只是Assign的值不同,但是Ruby卻會有不同的解釋(一個是Fixnum類別,另一個是String類別)

2.1.4.3 Punctuation in identifiers
下面這段是書上對於Variable Scope的範例:
http://gist.github.com/289500.js?file=gistfile1.rb

說實在的那樣寫對我這個白痴來說真的是很難理解,所以我又找到另外一個詳細的解說版本如下:
http://gist.github.com/289510.js?file=gistfile1.rb

是不是清楚許多了呀?最後在這邊再以一個小例子來收個尾:
http://gist.github.com/289511.js?file=gistfile1.rb

你這邊一定會說「媽呀,你根本就沒說到Instance variable和Class variables也想打混過去!!」,好吧,你都這樣說了,那我只好再想些例子來滿足你,先看看定義吧:

A class variable is a variable that is shared amongst all instances of a class. This means that only one variable value exists for all objects instantiated from this class. This means that if one object instance changes the value of the variable, that new value will essentially change for all other object instances.

Instance variables are similar to Class variables except that their values are local to specific instances of an object. For example if a class contains an instance variable called @total, if one instance of the object changes the current value of @total the change is local to only the object that made the change. Other objects of the same class have their own local copies of the variable which are independent of changes made in any other objects.

這邊就簡單的翻譯一下它的意思:

Class Variables(類別變數)就是一種可以在同一個類別下的實體物件間互相分享的一種變數,當有一個實體改變了它的值,另一個實體也會存取到被改變後的值。

而Instance Variables(實體變數)則是個別存在於各實體物件下,各自維護自己的實體變數,而不會互相產生衝突。

我知道大家一定不想看英文,我自己翻得也很爛XD,所以我自己用了一個智障簡報來講解一下,看看就好,別太在意,只是想讓大家笑一下XD

(SlideShare真是難看,用Keynote看才可以看到動畫說,我轉了一個Mov檔在下面!)
P.S.原本要直接Embed在文章裡面,不過Hax4.in有點慢…

大概就是這個意思啦,只是簡單解釋一下,反正之後用Code來說明會比較好了解。

參考:Click Me

[Ruby] Get started

最近因為一些實務上的需求(真的嗎),所以不得不試著嘗試用RoR來開發程式,但是因為萬事起頭難,最困難的就是在一開始,所以就先試著了解Ruby這個語言的特性,再來往下階段做開發。

因為說實在的,不知道為什麼國內Ruby相關的資源很少,在網路上都沒有找到什麼比較淺顯易懂的書,所以就隨性上網找到了一本名為「The Ruby Programming Language」的書,就拿它來當cookbook吧。

因為我是從PHP跑來這邊玩沙,所以說實在的我還真的有點很不習慣,先看一下PHP在Wiki上的介紹:

『PHP 原本的簡稱為 Personal Home Page[4],是Rasmus Lerdorf 為了要維護個人網頁,而用c語言開發的一些CGI工具程式集,來取代原先使用的 Perl 程式。最初這些工具程式用來顯示 Rasmus Lerdorf 的個人履歷,以及統計網頁流量[5]。他將這些程式和一些表單直譯器整合起來,稱為 PHP/FI。』– From Wiki

PHP當初是延用了C的風格,再加上一些自有的特色,使得其多了一些較彈性的設計(如使用變數時可以不需要宣告型態)。但是,當我看到Ruby之後,反而讓我有種很難上手的感覺,因為它好精簡,讓我有種當初在寫Perl的感覺(雖然我沒有寫好,對不起c9s XD)。

好啦,廢話不多說,現在就來看看我看這本書時的一些小重點。

3.2.1.4 Arbitrary delimiters for string literals

還記得剛剛為什麼我說它讓我覺得好像Perl嗎,因為它也有支援Syntax Sugar,來看看它是怎麼做到的:
http://gist.github.com/288795.js?file=gistfile1.rb
還真的是很簡單,只要在前面要加個”%”就可以了(Perl 只要 q就好了呀!!!)

下面還說到要怎麼在使用Syntax Sugar時再跳脫那些用來當標記的符號,我覺得如果真的還要這樣子就有點本末倒置了吧…

3.2.1.5 Here documents

這邊再把上面的Syntax Sugar做個延伸,是借用Unix shell的語法,叫做 Here documents,它後面的註解很有趣,它說「因為這個文件就在個原始碼內,而不是存在於外部的檔案」,真是有夠白痴,有講和沒講不是一樣XD。

來看個小Example。

http://gist.github.com/288819.js?file=gistfile1.rb

“<<"和"<<-"的差別就差在後者的close tag的前面可以有空白,但是前者的不行,就這樣子而已。還有個特別強調的地方,就是close tag的後面不能插入comment,插了就會出現一堆錯誤!!這個東西在PHP也有,通常是用來存放HTML的部分,這樣就不用一直一行一行的輸出,算是把View分離的方法,範例如下。

http://gist.github.com/288830.js?file=gistfile1.rb

1st part 就覺牛刀小試一下到這邊啦。