一绵载、心得體會(huì)
今天完成了什么
- 看了20頁的鎬頭書
- 學(xué)了bag的10個(gè)controller
收獲什么饲梭?
- 新增期吓、編輯都放在show視圖里
- 活動(dòng)平臺(tái)
- 訂單活動(dòng)
- 地址早歇、地址快照、品牌
二讨勤、讀書筆記
回顧昨天學(xué)到內(nèi)容
- 肯定匹配 =~
舉個(gè)栗子:
name = "ni shi da sha gua"
name =~ /a/ -> 8
匹配操作符返回匹配發(fā)生的字符位置箭跳,它們也有副作用,會(huì)設(shè)置一些Ruby變量潭千?谱姓??
$`得到匹配之前的那部分字符串刨晴,$'得到匹配之后的那部分字符串屉来。
所以,可以這么寫show_regexp方法狈癞,以說明具體的模式在何處發(fā)生匹配茄靠。
舉個(gè)栗子:
def show_regexp(a, re)
if a =~ re
"#{$` } <<#{$&}>>#{$' }"
else
"no match"
end
end
show_regexp('very interesting', /t/) -> very in <<t>>eresting
這個(gè)匹配也設(shè)置了線程局部變量(thread-local variables)?亿驾?嘹黔?,$~與$1直到$9莫瞬。
$~變量是MatchData對象儡蔓,它持有你想知道的有關(guān)匹配的所有信息。???
$1等持有匹配各個(gè)部分的值疼邀,我們在后面會(huì)談到這些喂江。對那些看到類似Perl變量名就心懷畏懼的人來講,請稍安勿躁得啦旁振!
關(guān)于模式
每個(gè)正則表達(dá)式包含一種模式获询,用來對字符串進(jìn)行正則表達(dá)式的匹配涨岁。
在模式內(nèi),除了.吉嚣,|梢薪,(,)尝哆,[秉撇,],{秋泄,}琐馆,+,\恒序,^瘦麸,$,*和?字符之外歧胁,所有字符串匹配它們本身滋饲。
注意:在這些特殊字符之前放置一個(gè)反斜線便可以匹配它們的字面量。舉個(gè)栗子:
show_regexp("yes | no", /\|/) -> yes <<|>> no
如果不加反斜線的話:
show_regexp("yes | no", /|/) -> <<>>yes | no
返回的竟然是:
<<>>yes | no
為什么會(huì)這樣呢与帆?
這是因?yàn)閨是特別字符了赌,未轉(zhuǎn)義的豎線要么匹配在它之前的正則表達(dá)式,要么匹配在它之后的正則表達(dá)式玄糟。
這里的豎線(|)前后都是空,所以匹配的也是空袄秩,匹配的順序是從左到右阵翎,所以就是上面那個(gè)樣子。
但是之剧,有些同學(xué)會(huì)疑惑郭卫,那到底是先匹配模式中豎線(|)的左邊還是豎線的右邊呢?讓我們來做個(gè)對照試驗(yàn)背稼。
舉個(gè)栗子:
show_regexp(" red ball blue sky", /red|/) -> <<red>> ball blue sky
show_regexp("red ball blue sky", /|red/) -> <<>>red ball blue sky
red放在左邊的時(shí)候贰军,能匹配出字符串中的red
而red放在右邊的時(shí)候,則不能匹配出字符串的red蟹肘,反而匹配的是空词疼。
這說明,前者在匹配的時(shí)候帘腹,是從模式中豎線的左邊和字符串中的最左邊的空開始匹配贰盗。
show_regexp("red ball blue sky", /red|blue/) -> <<red>> ball blue sky
show_regexp("red ball blue sky", /blue|red/) -> <<red>> ball blue sky
show_regexp("blue ball red sky", /red|blue/) -> <<blue>> ball red sky
show_regexp("blue ball red sky", /blue|red/) -> <<blue>> ball red sky
從上面的例子中,我們可以發(fā)現(xiàn)阳欲,無論匹配模式里的red和blue放在哪邊舵盈,結(jié)果都是一樣的陋率,所以。
但是秽晚,如果把匹配字符串里的blue和red交換位置瓦糟,我們會(huì)發(fā)現(xiàn),匹配出來的不是red赴蝇,竟然是blue狸页。
所以,無論是先匹配模式中豎線的左邊還是右邊扯再,都不會(huì)影響結(jié)果芍耘。
5.4.2基于模式的替換(Pattern-Based Substitution)
在字符串中能夠發(fā)現(xiàn)模式有時(shí)就已經(jīng)足夠好了,如果你的朋友給出難題熄阻,讓你找出順序包含字母a斋竞,b,c秃殉,d和e的詞坝初,你可能會(huì)使用模式/a.b.cd.e/去查找詞表并找出abjectedness,absconded钾军,ambuscade和carbacidometer這些詞等等鳄袍,這種事情肯定有價(jià)值的。
當(dāng)然吏恭,有時(shí)候待根據(jù)模式匹配去改變一些東西拗小,讓我們回到歌曲列表文件中,不管是誰樱哼,都會(huì)以小寫方式輸入歌曲演唱者的名字哀九,以混合大小寫方式在點(diǎn)唱機(jī)的屏幕上顯示它們會(huì)更好看,怎么樣才能把每個(gè)詞的首字符改成大寫呢搅幅?
String#sub和String#gsub方法超找出能夠匹配第一個(gè)參數(shù)的那部分字符串阅束,同時(shí)用第二個(gè)參數(shù)替換這它們。String#sub執(zhí)行一次替換茄唐,而String#gsub在匹配每次出現(xiàn)都進(jìn)行替換息裸。
兩個(gè)方法都返回了對含有這些替換字符串的新的拷貝。Mutator版本的String#sub沪编!和String#gsub!會(huì)直接修改原先的字符串呼盆。
a = "the quick brown fox"
a.sub(/[aeiou]/, '*')
a.gsub(/[aeiou]/, '*')
a.sub(/\s\S+/, '')
a.gsub(/\s\S+/, '')
兩個(gè)函數(shù)的第二個(gè)參數(shù)可以是String或block。如果使用block漾抬,匹配的字符串會(huì)被傳遞被block宿亡,同時(shí)block的結(jié)果值會(huì)被替換到原先的字符串中。
a = "the quick brown fox"
a.sub(/^./){|match| match.upcase}
a.gsub(/[aeiou]/) {|vowel| vowel.upcase}
所以纳令,對如何轉(zhuǎn)換歌曲演唱者名字的這個(gè)問題挽荠,我們給出了大難克胳。匹配詞的首字符的模式是\b\w——它尋找后面跟著詞字符(word character)的詞邊界。把這個(gè)模式和gsub結(jié)合起來圈匆,可以改變歌曲演唱者的名字了漠另。
def mixed_case(name)
name.gsub(/\b\w/) {|first| first.upcase}
end
mixed_case("fats waller")
mixed_case("louis armstrong")
mixed_case("strength in numbers")
替換中的反斜線序列
早些時(shí)候我們注意到序列\(zhòng)1和\2等在模式中可用,它們代表至今為止第n個(gè)已匹配的組跃赚,相同的序列也可以作為sub和gsub的第二個(gè)參數(shù)笆搓。
"fred:smith".sub(/(\w+):(\w+)/, '\2, \1')
"nercpyitno".gsub(/(.)(.)/, '\2\1')
其他的反斜線序列在替換字符串中起的作用:&(最后的匹配),+(最后匹配的組)纬傲,'(匹配之前的字符串)满败,'(匹配之后的字符串)和\(字面量反斜線)。
如果想在替換中包含字面量反斜線叹括,我們會(huì)變得很困惑算墨,顯然可以寫成:
str.gsub(/\\/, '\\\\')
很清楚,代碼正試圖用兩個(gè)反斜線替換str中的每個(gè)反斜線汁雷,程序員在替換文本中用了雙倍的反斜線净嘀,因?yàn)橹浪鼈冊谡Z法分析階段中會(huì)被轉(zhuǎn)化成\。但是當(dāng)替換發(fā)生時(shí)侠讯,正則表達(dá)式引擎對字符串又執(zhí)行了一遍挖藏,并把\轉(zhuǎn)換成\,所以最終結(jié)果是使用另外一個(gè)反斜線替換每個(gè)反斜線厢漩。需要把它寫成gsub(/\/, '\\\\')!
str = 'a\b\c'
str.gsub(/\/, '\\\\')
但是膜眠,如果利用&被替換為已匹配的字符串這個(gè)事實(shí),也可以寫成:
str = 'a\b\c'
str.gsub(/\/, '&&')
如果使用gsub的block形式袁翁,用來替換的字符串會(huì)被和僅被分析一次(在語法分析階段)柴底,這正是所希望看到的結(jié)果。
str = 'a\b\c'
str.gsub(/\/) { '\\' }
最后粱胜,下面的例子極好的表達(dá)了結(jié)合使用正則表達(dá)式和block,請參見由Wakou A編寫的CGI庫模塊的代碼片段狐树,這段代碼接受包含HTML轉(zhuǎn)義序列的字符串并把它轉(zhuǎn)換成普通的ASCII焙压。
為了支持日本用戶,它在正則表達(dá)式上使用了n修飾符關(guān)閉了寬字符處理抑钟,它也說明了Ruby的case表達(dá)式涯曲。
def unescapeHTML(string)
str = string.dup
str.gsub!(/&(.*?); /n) {
match = $1.dup
case match
when /\Aamp\z/ni then '&'
when /\Aquot\z/ni then '*'
when /\Agt\z/ni then '>'
when /\Alt\z/ni then '<'
when /\A#(\d+)\z\/n then Integer($1).chr
when /\A#x([0-9a-f]+)\z/ni then $1.hex.chr
end
}
str
end
puts unescapeHTML("1<2 & 4>3")
puts unescapeHTML(""A" = A = A")
輸出結(jié)果:
1<2 && 4>3
"A" = A = A
dup:復(fù)制對象沒有分配ID,并被視為新記錄在塔。請注意幻件,這是一個(gè)“淺”副本,因?yàn)樗鼉H復(fù)制對象的屬性蛔溃,而不是其關(guān)聯(lián)绰沥。 “深”副本的范圍是特定于應(yīng)用程序的篱蝇,因此由應(yīng)用程序根據(jù)需要進(jìn)行實(shí)施。 dup方法不保留時(shí)間戳(已創(chuàng)建|更新)_(at | on)徽曲。
5.4.3面向?qū)ο蟮恼齽t表達(dá)式(Object-Oritended Regular Expressions)
必須承認(rèn)零截,盡管所有這些古怪的變量用起來十分方便,但是它們不是面向?qū)ο蟮耐撼迹瑫r(shí)它們很神秘涧衙,難道我們沒有說Ruby的所有物體都是對象嗎?哪里出錯(cuò)了奥此?
真的沒有錯(cuò)弧哎,在Matz設(shè)計(jì)Ruby時(shí),他設(shè)計(jì)了一個(gè)完全面向?qū)ο蟮恼齽t表達(dá)處理系統(tǒng)稚虎,然后在它之上包裝(wrap)所有這些$變量撤嫩,使它們看起來對Perl程序員很熟悉。對象和類還在這里祥绞,只不過就在表面下非洲,讓我們花點(diǎn)時(shí)間把它們挖掘出來吧。
實(shí)際上已經(jīng)遇到一個(gè)類:正則表達(dá)式字面量創(chuàng)建了Regexp類的實(shí)例蜕径。
re = /cat/
re.class -> Regexp
Regexp#match方法對字符串匹配正則表達(dá)式两踏。如果失敗了,它返回nil兜喻。如果成功梦染,則返回MatchData類的一個(gè)實(shí)例。MatchData對象讓你訪問關(guān)于這次匹配的所有可用信息朴皆,所有這些好東西通過$變量得到的帕识,它們綁定在一個(gè)小巧方便的對象。
re = /(\d+):(\d+)/ # match a time hh:mm
md = re.match("Time: 12:34am")
md.class
md[0] # == $&
md[1] # == $1
md[2] # == $2
md.pre_match # == $`
md.post_match # == $'
匹配數(shù)據(jù)存儲(chǔ)在它自己的對象里遂铡,這樣可以同時(shí)保留兩個(gè)或多個(gè)模式匹配的結(jié)果肮疗,這些事情使用那些$變量是做不出來的。在下面的例子中扒接,對兩個(gè)字符串匹配相同的Regexp對象伪货,每次匹配返回唯一的MatchData對象,通過檢驗(yàn)兩個(gè)子模式字段來驗(yàn)證它钾怔。
re = /(\d+):(\d+)/
md1 = re.match("Time: 12:34am")
md2 = re.match("Time: 10:30pm")
md1[1, 2]
第6章
關(guān)于方法的更多細(xì)節(jié)(more about Methods)
6.1 定義一個(gè)方法
- 以小寫字母開頭
如果你使用大寫字符碱呼,并不會(huì)立即得到一個(gè)錯(cuò)誤,但是當(dāng)Ruby看到你調(diào)用這個(gè)方法時(shí)宗侦,它首先猜測這是一個(gè)常量愚臀,而不是一個(gè)方法調(diào)用,且結(jié)果是Ruby可能錯(cuò)誤地解析這個(gè)調(diào)用矾利。
- 表示查詢的方法名通常以?結(jié)尾姑裂,例如instance_of馋袜?
- “危險(xiǎn)的”或者會(huì)修改接收對象(receiver)的方法,可以用!結(jié)尾炭分,例如String提供了chop和chop!方法桃焕,第一個(gè)返回一個(gè)修改后的字符串;第二個(gè)則就地修改對象捧毛。
舉個(gè)栗子:
我們已經(jīng)新方法指定了一個(gè)名字观堂,可能還需要聲明某些參數(shù)(parameter,形參)呀忧,它們就是括號(hào)中列出的局部變量师痕。(方法參數(shù)兩邊的括號(hào)是可選的;我們的慣例是而账,當(dāng)方法有參數(shù)時(shí)則使用括號(hào)胰坟,否則忽略它們。)
def my_new_method(arg1, arg2, arg3)
#Code for the method would go there
end
Ruby可以讓你指定方法參數(shù)(argument泞辐,實(shí)參)的默認(rèn)值——如果調(diào)用者在傳入?yún)?shù)時(shí)沒有明確指定所使用的的值笔横。為此你可以使用賦值操作符。
def cool_dude(arg1="Miles", arg2="Coltrane", arg3="Roach")
"#{arg1}, #{arg2}, #{arg3}."
end
方法體內(nèi)是普通的Ruby表達(dá)式咐吼,你不能在方法內(nèi)定義非單件(nonsingleto)類或模塊吹缔。如果你在一個(gè)方法內(nèi)定義另一個(gè)方法,內(nèi)部的方法只有在外部執(zhí)行時(shí)才得到定義锯茄,方法的返回值是執(zhí)行的最后一個(gè)表達(dá)式的值厢塘,或者return表達(dá)式顯示返回的值。
6.1.1 可變長度的參數(shù)列表(Variable-Length Argument Lists)
但是如果你希望傳入可變個(gè)數(shù)的參數(shù)(argument)肌幽、或者想用一個(gè)形參(parameter)接收多個(gè)參數(shù)晚碾,在“普通”的參數(shù)名前放置一個(gè)星號(hào)(*)即可。
def varargs(arg1, *rest)
"Got #{arg1} and #{rest.join(', ')}"
end
varargs("one")
varargs("one", "two")
在這個(gè)栗子中喂急,和往常一樣第一個(gè)參數(shù)賦值給方法的第一個(gè)形參格嘁,不過,第二個(gè)形參的前綴為星號(hào)廊移,因此所有剩余的參數(shù)被裝入到一個(gè)新的Array中讥蔽,然后賦值給第二個(gè)形參。
6.1.2 方法和Block(methods and Blocks)
之前講過“Block和迭代器“画机,調(diào)用一個(gè)方法是,可以用一個(gè)block與之相關(guān)聯(lián)新症,通常步氏,您可以使用yield從方法內(nèi)部調(diào)用這個(gè)block。
def take_block(p1)
if block_given?
yield(p1)
else
p1
end
end
take_block("no block")
take_block("no block") {|s| s.sub(/no /, '')}
不過如果方法定義的最后一個(gè)參數(shù)前綴為&徒爹,那么所關(guān)聯(lián)的block會(huì)被轉(zhuǎn)換為一個(gè)Proc對象荚醒,然后賦值給這個(gè)參數(shù)芋类。
class TaxCalculator
def initialize(name, &block)
@name, @block = name, block
end
def get_tax(amount)
"#@name on #{amount} = #{ @block.call(amount) }"
end
end
tc = TaxCalculator.new("Sales tax") { |amt| amt * 0.075 }
tc.get_tax(100)
調(diào)用方法(Calling a Method)
你可以通過指定接受者、方法的名稱界阁、可選的參數(shù)及block侯繁,來調(diào)用一個(gè)方法。
connection.download_MP3("jitterbug") {|p| show_progress(p)}
在這個(gè)栗子中泡躯,connection對象是接收者贮竟,download_MP3是方法的名稱,”jitterbug“是參數(shù)较剃,花括號(hào)中的內(nèi)容是相關(guān)聯(lián)的block咕别。
對類方法或者模塊來說,接收者是類或模塊的名字写穴。
File.size("testfile")
Math.sin(Math::PI/4)
如果你省略了接收者惰拱,其默認(rèn)為self,也就是當(dāng)前的對象啊送。
self.class
self.frozen
Ruby正是用這種默認(rèn)的機(jī)制實(shí)現(xiàn)私有方法調(diào)用的偿短,我們無法調(diào)用某個(gè)接受對象的私有方法,它們只是在當(dāng)前對象(self)中是可用的馋没。
而在前面的栗子中昔逗,我們調(diào)用self.class時(shí)必須要指定一個(gè)接收對象,這是因?yàn)閏lass在Ruby中是一個(gè)關(guān)鍵字(它引入類的定義)披泪,因此單獨(dú)使用它會(huì)產(chǎn)生語法錯(cuò)誤纤子。
可選的參數(shù)跟隨在方法名之后,如果沒有二義性款票,在調(diào)用方法時(shí)控硼,你可以省略參數(shù)列表兩側(cè)的括號(hào),不過艾少,除非最簡單的情況卡乾,我們不推薦這樣做——某些微妙的問題可能會(huì)讓你犯錯(cuò)誤,我們的規(guī)則很簡單:只要你有任何疑慮缚够,就使用括號(hào)幔妨。
a = obj.hash
a = obj.hash()
obj.some_method
6.2.1 方法返回值(Method Return Values)
每個(gè)被調(diào)用的方法都會(huì)返回一個(gè)值(盡管沒有規(guī)定說你必須要使用這個(gè)值)。方法的值谍椅,是在方法執(zhí)行中最后一個(gè)語句執(zhí)行的結(jié)果误堡,Ruby有一個(gè)return語句,可以從當(dāng)前的執(zhí)行的方法中退出雏吭,return的返回值是其參數(shù)的值锁施,如果不需要return就省略之,這是Ruby的一個(gè)慣用技法。
def meth_one
"one"
end
meth_one
def meth_three
100.times do |num|
square = num*num
return num, square if square >1000
end
end
最后一種情況演示了悉抵,如果你給定return多個(gè)參數(shù)肩狂,方法會(huì)將它們以數(shù)組的形式返回。你可以使用并行賦值來收集返回值姥饰。
num, square = meth_three
在方法調(diào)用中的數(shù)組展開
我們最早看到傻谁,在方法定義中,如果你在一個(gè)正規(guī)參數(shù)前加一個(gè)星號(hào)列粪,那么傳入這個(gè)方法調(diào)用的多個(gè)參數(shù)將會(huì)被裝入一個(gè)數(shù)組中审磁,當(dāng)然,也有某些操作是相反的方式篱竭。
當(dāng)你調(diào)用一個(gè)方法時(shí)力图,你可以分解一個(gè)數(shù)組,這樣每個(gè)成員都視為單獨(dú)的參數(shù)掺逼。在數(shù)組參數(shù)(必須在所有普通參數(shù)的后面)前加一個(gè)星號(hào)完成這一點(diǎn)吃媒。
def five(a, b, c, d, e)
"I was passed #{a} # #{c} #rywwh7i #{e}"
end
five(1, 2, 3, 4, 5)
讓block更加動(dòng)態(tài)
我們已經(jīng)看到如何為方法調(diào)用關(guān)聯(lián)一個(gè)block吕喘。
list_bones("aardvark") do |bone|
...
end
一般來說赘那,這已經(jīng)足夠好了——你可以將一個(gè)固定的block關(guān)聯(lián)到方法,就如同在if或while語句之后編寫的一大塊代碼氯质。
但是募舟,某些時(shí)候,你希望更加靈活一些闻察,例如拱礁,我們希望教授一些算術(shù)技法,學(xué)生可能想要一個(gè)n次相加或相乘的表辕漂,如果學(xué)生需要一個(gè)2倍次的表呢灶,我們就輸出2,4钉嘹,6鸯乃,8等。
print "(t)imes or (p)lus:"
times = gets
print "number: "
number = Integer(gets)
if times =~ /^t/
puts ((1..10).collect {|n| n*number}.join(", "))
else
puts ((1..10).collect {|n| n+number}.join(", "))
end
這可以工作跋涣,不過在每個(gè)if語句之后重復(fù)實(shí)質(zhì)上等價(jià)的代碼缨睡,頗為丑陋,如果我們可以將完成計(jì)算的block抽取出來陈辱,代碼就漂亮富多了奖年。
print "(t)imes or (p)lus:"
times = gets
print "number: "
number = Integer(gets)
if times =~ /^t/
puts (lambda{|n| n*number})
else
puts (lambda {|n| n+number})
end
如果方法的最后一個(gè)參數(shù)前有&符號(hào),Ruby將認(rèn)為它是一個(gè)Proc對象沛贪,它會(huì)將其從參數(shù)列表中刪除拾并,并將Proc對象轉(zhuǎn)換為一個(gè)block揍堰,然后關(guān)聯(lián)到該方法。
收集散列參數(shù)
某些語言支持關(guān)鍵字參數(shù)——也就是你可以任意順序傳入?yún)?shù)的名稱與值嗅义,而非按指定順序傳入?yún)?shù)。
因?yàn)槲覀冊诒緯弦话嬷刑岬絉uby1.8將會(huì)支持這一特性隐砸,同時(shí)之碗,人們可以使用散列表來取得相同的效果,例如季希,可以考慮為我們的SongList加入更強(qiáng)大的按名搜索功能褪那。
class SongList
def create_search(name, params)
# ...
end
end
list.create_search("short jazz songs", {
'genre' => "jazz",
'duration_less_than' => 270
})
第一個(gè)參數(shù)是搜索的名字,第二個(gè)是一個(gè)散列式式塌,其中包括搜索的參數(shù)博敬。使用散列表意味著我們可以模擬關(guān)鍵字:查詢類型為”爵士樂“, 且時(shí)長小于4分半的歌曲峰尝。不過這種方式有點(diǎn)笨重偏窝,并且一組大括號(hào)容易誤寫為一個(gè)和方法關(guān)聯(lián)的block。
因此武学,Ruby提供了一種快捷方式祭往,只要在參數(shù)列表中,散列數(shù)組在正常的參數(shù)之后火窒,并位于任何數(shù)組或block參數(shù)之前硼补,你就可以使用鍵值對,所有的這些對會(huì)被集合到一個(gè)散列數(shù)組中熏矿,并作為方法的一個(gè)參數(shù)傳入已骇。無須使用大括號(hào)。
list.create_search('short jazz songs',
'genre'=>"jazz",
'duration'=>270
)
最后票编,Ruby的慣用技法是褪储,你可以使用符號(hào)(Symbol)而非字符串作為參數(shù),符號(hào)清楚地表達(dá)了你所引用的是某個(gè)事物的名字栏妖。
list.create_search('short jazz songs',
:genre => :jazz,
:duration = 270
)
一個(gè)潛心編寫的Ruby程序通常包括許多方法乱豆,每個(gè)都很短小,因此熟悉定義和使用Ruby方法的各種選擇是非常值得的吊趾。
第七章 表達(dá)式(Expression)
Ruby和其他語言的一個(gè)不同之處就是任何東西都可能返回一個(gè)值:幾乎所有東西都是表達(dá)式宛裕。
明顯的一個(gè)好處就是實(shí)現(xiàn)鏈?zhǔn)秸Z句。
a = b = c = 0
[3, 1, 7, 0].sort.reverse
不太明顯的好處是论泛,C和Java中的普通語句在Ruby中也是表達(dá)式揩尸,例如,if和case語句都返回最后執(zhí)行的表達(dá)式的值屁奏。
song_type = if song.mp3_type == MP3::Jazz
if song.written < Date.new(1935, 1, 1)
Song::TradJazz
else
Song::Jazz
end
else
Song::other
end
rating = case votes_cast
when 0...10 then Rating::SkipThisOne
when 10...50 then Rating::CouldDoBetter
else Rating::Rave
end
運(yùn)算符表達(dá)式(Operator Expression)
Ruby提供了基本的運(yùn)算符集(如+岩榆、-、*、/等等),也提供了幾個(gè)獨(dú)特的運(yùn)算符勇边。
實(shí)際上犹撒,Ruby中的許多運(yùn)算符是由方法調(diào)用來實(shí)現(xiàn)的,例如粒褒,當(dāng)你執(zhí)行 ab+c時(shí)识颊,實(shí)際上你是請求a對象執(zhí)行方法,傳入的參數(shù)是b奕坟。然后請求返回的結(jié)果對象執(zhí)行+方法祥款,傳入的參數(shù)是c。這等價(jià)于:
(a.*(b).+c)
因?yàn)槿魏螙|西都是對象月杉,而且你可以重新定義實(shí)例方法刃跛,所以你可以重新定義任何不滿足你需求的基本算術(shù)方法。
class Fixnum
alias old_plus + # we can reference the original '+' as 'old_plus'
# Redefine addition of Fixnums. This
# is a BAD IDEA
def +(other)
old_plus(other).succ
end
end
更有用的是苛萎,你寫的類可以像內(nèi)建那樣參與到運(yùn)算符表達(dá)式中桨昙,比如,你可能香蔥歌曲中間剪輯一段首懈,這可以用索引操作來實(shí)現(xiàn)绊率。
class Song
def [](from_time, to_time)
result = Song.new(self.title + " [extract]"),
self.artist
to_time - from_time
result.set_start_time(from_time)
result
end
end
這段代碼擴(kuò)展了類Song:提供了[]方法,該方法有兩個(gè)參數(shù)(開始時(shí)間和結(jié)束時(shí)間)究履。它返回對應(yīng)給定時(shí)間間隔的一個(gè)新的song對象滤否。我們可以通過下面的代碼來試聽一首歌:
song[0, 15].play
7.2 表達(dá)式之雜項(xiàng)
除了支持明顯的運(yùn)算符表達(dá)式和方法調(diào)用,以及不太明顯的語句表達(dá)(例如if和case)外最仑,Ruby的表達(dá)式還支持更多的東西藐俺。
7.2.1命令展開(Command Expansion)
如果你用反索引號(hào)(`), 或者以%x為前綴的分界形式泥彤,括起一個(gè)字符串欲芹,默認(rèn)情況下它會(huì)被當(dāng)做底層操作系統(tǒng)的命令來執(zhí)行。表達(dá)式的返回值就是該命令的標(biāo)準(zhǔn)輸出吟吝,由于沒有去處新行符菱父,所以你獲得的返回值結(jié)尾可能會(huì)有回車符或者換行符。
`date`
`ls`.split[34]
%x{echo "Hello there"}
你也可以在命令字符串中使用表達(dá)式展開和所有普通的轉(zhuǎn)義序列剑逃。
for i in 0..3
status = 'dbmanager status id=#{1}'
# ...
end
命令的退出狀態(tài)(exit status)保存在全局變量$?中浙宜。
重定義反引號(hào)
在前面的描述中,我們說反引號(hào)括起來的字符串”默認(rèn)“被當(dāng)做命令執(zhí)行蛹磺。實(shí)際上粟瞬,字符串被傳遞給了名為Kernel.方法(單引號(hào))。如果你愿意萤捆,可以重載它裙品。
alias old_backquote
def `(cmd)
result = old_backquote(cmd)
if $? !=0
fail "Command #{cmd} failed: #$?"
end
result
end
print `data`
print `data`