一、心得體會(huì)
1、今天完成了什么夺欲?
- 看了Ruby核心跪帝、Duck typing、類與對(duì)象些阅、RUby安全
- 看10個(gè)controller
2伞剑、今天收獲了什么?
- 類對(duì)象的類型不是類
- 什么是module
- 什么是代理類
- 10個(gè)controller:工單日志(Ticketschanges)市埋、工單(tickets)黎泣、加急原因、登記缤谎、倉庫(warehouses)抒倚、話術(shù)(words)、師傅(workers)坷澡、小組規(guī)則托呕、案例標(biāo)簽(case_tags)、案例(cases)
3频敛、今天犯了哪些錯(cuò)誤项郊?
4、今天的狀態(tài)如何斟赚? - 今天狀態(tài)爆表着降,看完了鎬頭書,還把rails-guide快速瀏覽了一遍拗军,覺得比鎬頭書要容易些任洞,兩天內(nèi)看完。
5食绿、明天還需要做什么侈咕? - 明天好好計(jì)劃怎么在兩天之內(nèi)把rails書看完
- 計(jì)劃看一半
二、讀書筆記
22.6 方法參數(shù)
22.7 調(diào)用方法(Invoking a Method)
開頭的形參將被賦值給方法的實(shí)際參數(shù)器紧,這些形參后面可以有一個(gè)key=>value配對(duì)的列表,這些key=>value對(duì)被將收集到一個(gè)新的Hash對(duì)象中楼眷,并作為一個(gè)形參傳入方法铲汪。
這些形參后面可以是一個(gè)前面帶星號(hào)的參數(shù),如果這個(gè)形參是一個(gè)數(shù)組罐柳,那么Ruby將用相應(yīng)的數(shù)組元素掌腰,將它替換為零或多個(gè)形參。
def regular(a, b, *c)
end
block可以關(guān)聯(lián)一個(gè)方法調(diào)用张吉,該調(diào)用可以使用字面量形式的block(它必須和調(diào)用的最后一行在同一行上)齿梁,也可以關(guān)聯(lián)一個(gè)參數(shù),該參數(shù)包含帶有&符號(hào)的Proc或Method對(duì)象的引用,不管block參數(shù)存在與否勺择,Ruby使用全局函數(shù)Kernel.block_given?的值來判斷是否存在與本調(diào)用相關(guān)聯(lián)的block创南。
a_proc = lambda{ 99 }
an_array = [ 98, 97, 96]
def block
yield
end
block { }
block do
end
block(&a_proc)
def all(a, b, c, *d, &e)
puts "a = #{a.inspect}"
puts "b = #{b.inspect}"
puts "c = #{c.inspect}"
puts "d = #{d.inspect}"
puts "block = #{yield(e).inspect}"
end
all('test', 1 => 'cat', 2 => 'dog', *an_array)
Foo.bar() #方法調(diào)用
Foo.bar #方法調(diào)用
Foo::bar() #方法調(diào)用
Foo::bar #訪問常量
方法的返回值是執(zhí)行的最后一個(gè)表達(dá)式的值。
return []
return表達(dá)式會(huì)立即退出方法省核,如果不帶參數(shù)調(diào)用return稿辙,則return的返回值為nil,如果帶一個(gè)參數(shù)气忠,則返回該參數(shù)的值邻储,如果參數(shù)多于一個(gè),則返回一個(gè)包含所有參數(shù)值的數(shù)組旧噪。
22.7.1 super
在方法體內(nèi)吨娜,調(diào)用super就像調(diào)用原方法一樣,不過是在含有原方法的對(duì)象的超類中搜索方法體淘钟,如果沒有參數(shù)(且未加括號(hào))傳遞給super萌壳,則原方法的參數(shù)將作為super的參數(shù),否則日月,super的參數(shù)將被傳遞袱瓮。
22.7.2 操作符方法(Operator Methods)
如果操作符表達(dá)式中的操作符是一個(gè)可重新定義的方法,Ruby像調(diào)用如下表達(dá)式那樣執(zhí)行操作符表達(dá)式爱咬。
22.7.3 屬性賦值(Attribute Assignment)
當(dāng)receiver.attrname作為左值出現(xiàn)時(shí)尺借,Ruby將調(diào)用接收者中名為attrname=方法,并以右值作為其唯一參數(shù)精拟,這種賦值語句的返回值是rvalue的值——attrname=的返回值將被拋棄燎斩。
如果你想訪問返回值(多半情況下不是rvalue的值),那么向方法發(fā)送一個(gè)顯式的消息
class Demo
attr_reader :attr
def attr=(val)
@attr = val
"return value"
end
end
d = Demo.new
22.7.4 元素引用操作符(Element Reference Operator)
receiver[expr[,expr]...]
receiver[expr[,expr]...] = rvalue
當(dāng)用作右值時(shí)蜂绎,元素引用調(diào)用接收者的[]方法栅表,并以方括號(hào)中的表達(dá)式作為參數(shù)傳遞。## 师枣?怪瓶??践美?不懂
22.8 別名(aliasing)
alias new_name old_name
將創(chuàng)建一個(gè)引用已有的方法洗贰、操作符、全局變量或正則表達(dá)式向后引用的新名字
當(dāng)為方法起別名字陨倡,新的名字將指向原方法體的一個(gè)拷貝敛滋,即使后來方法被重新定義了,別名仍舊會(huì)調(diào)用原來的方法實(shí)現(xiàn)代碼兴革。
def meth
"original method"
end
alias origi meth
def meth
"new and improved"
end
meth
origi
22.9 類定義(Class Definition)
Ruby的類定義通過執(zhí)行類代碼體創(chuàng)建或者擴(kuò)展類Class的對(duì)象绎晃。第一種形式中蜜唾,一個(gè)命名類將被創(chuàng)建或擴(kuò)展。生成的對(duì)象將被賦給名為classname的常量庶艾。
這個(gè)名字應(yīng)該以一個(gè)大寫字母開頭袁余,在第二種形式中,一個(gè)匿名類會(huì)和指定的對(duì)象相關(guān)聯(lián)落竹。
如果superexpr存在泌霍,那么它應(yīng)當(dāng)是一個(gè)以Class對(duì)象為結(jié)果的表達(dá)式,而且它也將是被定義的類的超類述召,如果省略了superexpr朱转,則默認(rèn)為類Object。
在方法體內(nèi)积暖,隨著各種定義代碼的讀入藤为,大多數(shù)Ruby表達(dá)式將被執(zhí)行。然而:
- 方法定義將在類的對(duì)象的一個(gè)表中注冊(cè)該方法夺刑。
- 嵌套的類和模塊定義將被存儲(chǔ)在類的常量中缅疟,而不是全局常量中。
module NameSpace
class Example
CONST = 123
end
end
obj = NameSpace::Example.new
a = NameSpace::Example::CONST
方法Module#include將把命名的模塊添作被定義的類的匿名超類遍愿。
使用域作用符(::)可以為類定義中的classname前置一個(gè)已存在的類或模塊名存淫。這種語法會(huì)將新的定義插入到前面已定義的模塊或類的名字空間,但不是在這些外部類的作用域中解釋此定義沼填。
在下面的例子中桅咆,類C被插入到模塊A的作用域,但并不是A的上下文中進(jìn)行解釋坞笙。結(jié)果岩饼,對(duì)CONST的引用被解釋成該名字對(duì)應(yīng)的頂層常量而不是A的常量,而且我們必須使用單例方法的全名薛夜,因?yàn)樵贏::C的上下文籍茧,C本身不是一個(gè)已知的常量。
CONST = "outer"
module A
CONST = "inner"
end
module A
class begin
def B.get_const
CONST
end
end
end
A::B.get_const
class A::C
def (A::C).get_const
CONST
end
end
A::C.get_const
22.9.1 從類中創(chuàng)建對(duì)象(Creating Objects from Classes)
類class定義的實(shí)例方法class#new將被創(chuàng)建接收者對(duì)應(yīng)的類的對(duì)象梯澜。這是通過調(diào)用classexpr.allocate來完成的寞冯,你可以重載此方法,但是你的實(shí)現(xiàn)必須返回正確的類的對(duì)象腊徙,然后它調(diào)用新創(chuàng)建的對(duì)象的initialize简十,并將傳遞給new的參數(shù)傳遞給initialize。
如果類定義中重載了類方法new撬腾,并且new沒有調(diào)用super,那么將無法創(chuàng)建該類的對(duì)象恢恼,并且調(diào)用new將返回nil民傻。
和其他方法一樣,initialize應(yīng)該調(diào)用super,以保證父類被適當(dāng)?shù)某跏蓟焯撸绻割愂荗bject牵署,則不需要這么做,因?yàn)镺bject類不做任何實(shí)例相關(guān)的初始化喧半。
22.9.2 類屬性聲明(Class Attribute Declarations)
類屬性聲明不是Ruby語法的一部分:它們不過是定義在類Module中的方法奴迅,該方法會(huì)自動(dòng)創(chuàng)建訪問類屬性的方法。
class name
attr attribute
attr_reader attribute
attr_writer attribute
attr_accessor attribute
end
22.10 模塊定義(Module Definitions)
module name
body
end
模塊基本上是一個(gè)不能被實(shí)例化的類挺据,和類一樣取具,在定義過程中模塊體將被執(zhí)行,生成的模塊Module對(duì)象被存儲(chǔ)在一個(gè)常量中扁耐,模塊中可以含有類方法和實(shí)例方法暇检。也可以定義常量和類變量。和類一樣婉称,通過使用Module對(duì)象作為接收者調(diào)用模塊方法块仆,通過使用“::”域作用符來訪問常量。
CONST = "outer"
module Mod
CONST = 1
def Mod.method1
CONST + 1
end
end
module Mod::Inner
def (Mod::Inner).method2
CONST + " scope"
end
end
Mod::CONST
Mod.method1
Mod::Inner::method2
22.10.1 Mixins——混入模塊(Mixins——including Modules)
class | module name
include expr
end
使用include方法可以將一個(gè)模塊包含到另一個(gè)模塊或者類的定義中王暗,含有include的模塊或類定義可以訪問它所包含模塊的常量悔据、類變量和實(shí)例方法。
如果一個(gè)模塊被包括到一個(gè)類定義中俗壹,那么模塊的常量科汗、類變量和實(shí)例方法實(shí)際上被綁定到該類的一個(gè)匿名(且不可訪問)超類中,類的對(duì)象會(huì)響應(yīng)發(fā)送給模塊實(shí)例方法的消息策肝。
模塊函數(shù)
盡管include在提供mixin功能時(shí)很有用肛捍,它也可以把模塊的常量、類變量和實(shí)例方法帶入到另一個(gè)名字空間中之众,然而拙毫,實(shí)例方法定義的功能不能通過模塊方法的實(shí)現(xiàn)。
module Math
def sin(x)
end
end
方法Module#module_function通過拷貝一個(gè)或多個(gè)模塊實(shí)例方法的定義來創(chuàng)建相應(yīng)的模塊方法來解決問題棺禾。
module Math
def sin(x)
end
end
實(shí)例方法和模塊方法是兩個(gè)不同的方法:方法定義被module_function拷貝出來而不是建立別名缀蹄。
訪問控制
22.12 Blocks,Closure和Proc對(duì)象
代碼block是closure膘婶;它能記住其被定義時(shí)的上下文缺前,并在被調(diào)用時(shí)使用該上下文。上下文中包含self的值悬襟、常量衅码、類常量、局部變量和任意被截獲的block脊岳。
class Holder
CONST = 100
def call_block
a= 101
@a = 102
@@q = 103
yield
end
end
class Creator
CONST = 0
def create_block
a = 1
@a = 2
@@a = 3
proc do
puts "a = #{a}"
puts "@a = #@a"
puts "@@a = #@@a"
puts yield
end
end
end
block = Creator.new.create_block { "original" }
Holder.new.call_block(&block)
返回結(jié)果:
a = 1
@a = 2
@@a = 3
original
WHY?????
22.12.1 Proc對(duì)象逝段,break和next
什么是block垛玻?
是和方法相關(guān)聯(lián)的一堆代碼,并在它們被定義的上下文運(yùn)作奶躯。
Block不是對(duì)象帚桩,但是它們能被轉(zhuǎn)換成類proc的對(duì)象。
有3中方式將block轉(zhuǎn)換成proc對(duì)象嘹黔。
- 通過傳遞block給一個(gè)方法账嚎,該方法的最后一個(gè)參數(shù)前有一個(gè)地址符&。該參數(shù)會(huì)接受block作為Proc對(duì)象儡蔓。
def meth1(p1, p2, &block)
puts block.inspect
end
meth1(1,2) {"a block"}
meth1(3,4)
- 通過調(diào)用Proc.new郭蕉,再將它和block關(guān)聯(lián)。
block = Proc.new { "a block" }
block
- 通過調(diào)用方法Kernel.lambda關(guān)聯(lián)block到方法調(diào)用
block = lambda{ "a block" }
block
前面兩種風(fēng)格的Proc對(duì)象在使用時(shí)是相同的浙值。我們稱這些對(duì)象為raw procs恳不。第三種風(fēng)格,由lambda生成开呐,為了Proc對(duì)象添加一些額外的功能烟勋,我們很快就能看到,我們稱這種對(duì)象為lambdas筐付。
無論在哪種block內(nèi)卵惦,next語句將退出block。block的值是傳遞給next的值瓦戚,如果沒有值傳遞給next沮尿,則為nil。
def meth
res = yield
"The block returns #{res}"
end
meth {next 99}
pr = Proc.new {next 99}
pr.call
pr = lambda {next 99}
pr.call
在raw proc中较解,break語句可以終止調(diào)用block犯法畜疾,方法的返回值為傳遞給break的參數(shù)。
22.12.2
return和block
處于作用域block內(nèi)的return和該作用域的return一樣印衔,block內(nèi)原上下文不再有效的return會(huì)引發(fā)異常啡捶。
22.13 引發(fā)異常(Raising EXceptions)
raise
raise string
raise thing
第一種形式重新引發(fā)$!中存儲(chǔ)異常,如果$!是nil奸焙,則引發(fā)一個(gè)新的RuntimeError瞎暑。
第二種形式創(chuàng)建一個(gè)新的RuntimeError異常,并設(shè)置其消息為給定的字符串与帆。
第三種形式通過在其第一個(gè)參數(shù)上調(diào)用Exception方法創(chuàng)建一個(gè)異常對(duì)象了赌,然后設(shè)置異常消息和調(diào)用棧為第二個(gè)和第三個(gè)參數(shù)。
類Exception和其對(duì)象含有一個(gè)稱為exception的工廠方法玄糟,所以異常類的名字和實(shí)例可以用作raise的第一個(gè)參數(shù)勿她。
當(dāng)異常發(fā)生時(shí),Ruby會(huì)將異常對(duì)象的引用存儲(chǔ)在全局變量$!中阵翎。
22.13.2 處理異常(HandingExceptions)
rescue expr
Rescue語句修飾符
一條語句可以含有一個(gè)可選的rescue修飾符嫂拴,該修飾符后跟另一條語句播揪。
22.14 Catch和Throw
方法Kernel.catch將執(zhí)行與之相關(guān)聯(lián)的block贮喧。
catch (symbol | string) do
block
end
方法Kernel.throw將中斷語句的正常執(zhí)行筒狠。
throw(symbol | string[, obj])
當(dāng)throw執(zhí)行時(shí),Ruby在調(diào)用棧中向上搜索直到找到匹配符號(hào)或字符串的第一個(gè)catch block箱沦。
如果找到辩恼,則搜索結(jié)束,并從被捕獲的block后面繼續(xù)執(zhí)行谓形,如果throw的第二個(gè)參數(shù)存在灶伊,那么它的值將作為catch的值返回。
第23章 Duck Typing
你應(yīng)該注意到:Ruby中沒有聲明變量和方法的類型寒跳。
23.1 Classes aren't types
duck typing哲學(xué):對(duì)象的類型是根據(jù)它能做什么而不是根據(jù)它的類決定的聘萨。
23.3 標(biāo)準(zhǔn)協(xié)議和強(qiáng)制轉(zhuǎn)換
Ruby提供了轉(zhuǎn)換協(xié)議(conversion protocals)的概念——對(duì)象可以選擇把自己轉(zhuǎn)換成另一個(gè)類的對(duì)象。
Ruby有三種標(biāo)準(zhǔn)的方式實(shí)現(xiàn)它童太。
我們已經(jīng)遇到了第一種:to_i和to_s方法分別把他們的接收者轉(zhuǎn)換成字符串和整數(shù)米辐。
這些轉(zhuǎn)換方法不是嚴(yán)格的:比如,如果對(duì)象有某種得體的字符串表示书释,它可能會(huì)有to_s方法翘贮。
為了返回?cái)?shù)字的字符串表示,我們的Roman類可能會(huì)實(shí)現(xiàn)to_s方法爆惧。
第二種形式的轉(zhuǎn)換函數(shù)使用名字如to_str何to_int的方法狸页。
class OneTwo
def to_ary
[1, 2]
end
end
ot = OneTwo.new
a, b = ot
puts "a = #{a}, b = #"
printf("%d--%d\n", *ot)
to_hash
to_int
to_in
to_proc
23.3.1 數(shù)字強(qiáng)制轉(zhuǎn)換
coerce
23.4 該做的做扯再,該說的說(Walk the walk芍耘, Talk the Talk)
第24章 類與對(duì)象
類與對(duì)象無疑是Ruby的中心,但是第一眼看上去可能讓人有點(diǎn)困惑熄阻,
一個(gè)RUby對(duì)象有三個(gè)部分:一組標(biāo)志斋竞、一些實(shí)例變量、以及相關(guān)聯(lián)的類饺律。
24.1 類與對(duì)象是如何工作的
所有的類/對(duì)象的交互窃页,都是使用上面給出的簡單模型解釋的:對(duì)象引用類,而類引用零個(gè)或多個(gè)類复濒,不過脖卖,實(shí)現(xiàn)細(xì)節(jié)可能有些詭異。
一個(gè)基本對(duì)象巧颈、以及它的類和超類
class Guitar
def paly()
end
end
lu = Guitar.new
24.1.1 你的基本的畦木、日常對(duì)象(Your Basic, Everyday Object)
24.1.2 什么是Meta(What's the Meta?)
24.1.3 特定于Object的類(Object-Specific Classes)
Ruby允許你創(chuàng)建一個(gè)和特定對(duì)象綁定的類。
24.1.4 Mixin
24.1.3 擴(kuò)展對(duì)象(extending objects)
24.4 繼承與可見性(Inheritance and Visibility)
關(guān)于類繼承最后一個(gè)詭秘的地方砸泛,十分含糊十籍。
在一個(gè)類定義中蛆封,你可以修改祖先類中方法的可見性,例如勾栗,你可以像下面這樣:
class Base
def aMethod
puts "Got here"
end
private :aMethod
end
class Derived1 < Base
public :aMethod
end
class Derived2 < Base
end
在這個(gè)例子中惨篱,我們可以調(diào)用D1類實(shí)例中的aMethod,但不能通過Base或D2的實(shí)例來調(diào)用它围俘。
那么Ruby是如何輾轉(zhuǎn)讓一個(gè)方法有兩個(gè)不同的可見性呢砸讳?
如果一個(gè)子類改變了父類中某個(gè)方法的可見性,Ruby實(shí)際上在子類中插入了一個(gè)隱藏的代理方法界牡,使用了super調(diào)用原來的方法簿寂,然后,它將這個(gè)代理的可見性設(shè)置為你所需要的宿亡。這意味著常遂,下面的代碼:
class Derived1 < Base
public :aMethod
end
實(shí)際上等同于:
class Derived < Base
def aMethod(*arg)
super
end
public :aMethod
end
super調(diào)用可以訪問父類中的方法,而不管其可見性挽荠,所以重寫方法可以讓子類覆寫父類中的可見性規(guī)則克胳。
24.5 凍結(jié)對(duì)象(freezing Objects)
有時(shí)候你費(fèi)盡力氣才讓你的對(duì)象完全正確,如果允許其他人可以改變它坤按。
第25章 Ruby安全
Walter Webcoder是一個(gè)非常棒的想法:
require 'benchmark'
include Benchmark
test = "Stormy Weather"
m = test.method(:length)
n = 100000
bm(12) { |x|
x.report("call") {n.times {m.call}}
x.report("send") {n.times {test.send(:length)}}
x.report("eval") {n.times {eval "test.length"}}
}
26.4 系統(tǒng)鉤子(System Hooks)
鉤子是一個(gè)跟蹤(trap)一些Ruby事件的技術(shù)毯欣,比如跟蹤對(duì)象創(chuàng)建,在Ruby中臭脓,最簡單的hook技術(shù)是截取程序執(zhí)行的系統(tǒng)命令酗钞,可能你想記錄程序執(zhí)行的所有操作系統(tǒng)命令。
只要重命名Kernel.system方法来累,用你自己的Kernel.system替換它就可以了砚作。
module Kernel
alias_method :old_system, :system
def system(*arg)
result = old_system(*arg)
puts "system(#{args.join(', ')}) returned #{result}"
result
end
end
system("date")
system("kan", "happ")
26.6 列集和分布式Ruby
Java提供了序列化(serialize)對(duì)象的特性,可以在某處保存對(duì)象嘹锁,并且需要的話可以重建(reconstitute)它們葫录,比如可以使用這個(gè)功能保存一個(gè)對(duì)象樹,這些對(duì)象樹表示某部分程序的狀態(tài)——一份文檔领猾、一小段音樂
Ruby把這種類型的序列化成為列集(marshaling)米同。可以使用Marshal.dump方法來保存一個(gè)對(duì)象和它的部分或所有組成對(duì)象(component)摔竿。
26.6.3分布式Ruby(Distributed Ruby)
使用drd的Ruby進(jìn)程可能會(huì)作為服務(wù)器面粮、客戶機(jī)或者兩者都是,drd服務(wù)器是對(duì)象的源继低,而客戶機(jī)是對(duì)象的使用者熬苍,對(duì)客戶機(jī)來說。
26.7 編譯時(shí)?運(yùn)行時(shí)柴底?任何時(shí)婿脸?(Compile、Runtime柄驻、Anytime)
使用Ruby要記住的一件重要事情是:在“編譯時(shí)”和“運(yùn)行時(shí)”之間沒有太大的差別狐树,它們都是相同的,可以向一個(gè)正運(yùn)行的進(jìn)程添加代碼凿歼。
方法
- sort! 對(duì)數(shù)組進(jìn)行排序褪迟,在排序的過程中arr將被凍結(jié)
a = ['a', 'b', 'e', 'c']
a.sort! -> ["a", "b", "c", "e"]
a -> ["a", "b", "c", "e"]
如果去掉!,a的狀態(tài)不變
a = ['a', 'b', 'e', 'c']
a.sort -> ["a", "b", "c", "e"]
a -> ['a', 'b', 'e', 'c']
Rails-guide
- 5分鐘快速瀏覽