亂七八糟的Ruby筆記

全當爲了體會Rails的魅力,學學基礎Ruby,摘自鋤頭書,其實這本書的後半本比較精華一些

輸出字符串的方法:可以使用puts與print,如果需要帶換行,可以在裏面加入\n符,可以使用#{}帶參數寫入字符串中,在1.9中,可以使用p 縮寫打印語句(puts, or println)
生成類的實例的方式
ClassName.new(args) ...

命名的一些規範
類定義:
class Name
.....
end
類名必須大寫首字母

方法的定義
def methodName
...
end
方法名小寫開頭

進行方法調用時候,可以忽略()的使用,同樣在定義不帶參數方法時,也可以不帶(), 進行方法調用時,也可以忽略()

因爲Ruby是純粹的面向對象的方法,所以其所有的對象都擁有完全的方法,不像Java的基本類型

ruby class中常用的變量定義方式
局部變量,方法參數,方法名都必須使用小寫字母,或者下劃線開頭
全局變量使用$開頭
實例變量使用@開頭
類變量使用@@開頭
類名,module,構造函數名稱均要以一個大寫字母開頭
一般來說,對於變量名,多使用_下劃線的方式進行多字母的組合,而類名使用首字母大寫的方式AxxBxx...

Array and Hashes
a=[] //聲明一個數組,訪問的方式一樣使用[index],也可以使用animals = %w( ant bee cat dog elk )
a={"key" => "value"} 用於聲明hashes字典 訪問的方式[key]
Hash.new(0) //用於創建value默認值爲0的hash對象
另外一種字典的定義方式
inst_section = {:cello => 'string'} 使用:key 代替字符串的"key", 也可以使用key:value的1.9新語法
注意訪問時,也需要使用對應的hash[:key]

邏輯判斷 if...elsif...else...end
也有按照英文語法的
puts "Danger, Will Robinson" if radiation > 3000 //同理可以應用在其他控制流語句之上

正則表達式
使用/...../ 格式進行聲明,類似字符串,也是一種單獨獨立的對象
進行調用的方式. str=~/reg/ 用於判斷str是否符合正則的要求,返回boolean值
sub ,替換首個符合的字符串,
gsub,替換所有符合的字符串 //上述均爲字符串方法
更多的是使用字符串來調用正則對象

代碼塊block的使用,用於提供小塊可傳遞的方法

block兩種定義的方式:
{puts hello}
do
xxx
end
可以將block作爲參數,或者附帶在參數後進行傳遞到方法中
verbose_greet("Dave", "loyal customer") { puts "Hi" }
在方法中,使用yield 調用傳入的block塊
同理,也可以傳遞參數給block中
def who_says_what
yield("Dave", "hello")
yield("Andy", "goodbye")
end
who_says_what {|person, phrase| puts "#{person} says #{phrase}" //與groovy中的基本一致

迭代器,用於便捷的輸出集合數組
animals.each {|animal| puts animal } //類似groovy中默認的it,對於數字也內置了循環的方法
5.times { print "*" }
3.upto(6) {|i| print i }
('a'..'e').each {|char| print char }

printf,類似StringFormat,或者System.out.printf的方式,使用變量生成所需的字符串
printf("Number: %5.2f,\nString: %s\n", 1.23, "hello") //只是變的更短了

讀取IO或者鍵盤輸入的方式
line = gets
print line
對於長篇的文章,需要使用while進行循環多行的讀取

當使用命令行執行時,可以使用ARGV 以數組方式獲取所附帶的參數

initialize 方法,將會在調用class.new方法時被執行,可以通過new傳遞參數,應該作用與java過得構造函數一樣
可以將傳入的變量設置爲@,實例變量,這裏區別Java的方式,不需要在外部聲明一個對象,@符號定義的變量,將會在類實例內部共享訪問

toString() 方法 to_s(),方法返回的方式與Java類似,只需返回一個字符串,注意使用p和puts打印輸出的內容並不相同,前者更詳細一些,後者與print一致,只打出對象所在內存位置

對實例變量的訪問,默認並不能直接訪問@定義的變量,可以通過定義同名方法進行讀取
def isbn
@isbn
end
也可以使用簡單的 attr_reader屬性,用於讀取實例變量(只讀)
attr_reader :isbn, :price
如果要修改實例變量,可以定義指定格式的方法 =結尾
def price=(new_price)
@price = new_price
end
也可以使用方便的
attr_writer :price
最簡單的方式(可讀寫):
attr_accessor :price

可以將外部可以訪問的實例變量成爲屬性
require 'csv' 用於導入cvs模塊
require_relative 'book_in_stock' 用於導入book_in_stock類

[]<< obj 可以使用<< 將一個對象放入數組中

Access Control 訪問控制
Ruby中一樣有public protected,private 三種訪問權限
方法默認都是public,除了initialize方法(始終是private)

設置的方式
protected # subsequent methods will be 'protected'
def method2 # will be 'protected'
#...
end
private # subsequent methods will be 'private'
def method3 # will be 'private'
#...
end
public # subsequent methods will be 'public'
def method4 # so this will be 'public'
#...
end

也可以使用統一定義的方式
public :method1, :method4
protected :method2
private :method3

Ruby中的字符串可以直接通過[index]進行修改字符

Containers, Blocks,and Iterators 容器,塊,迭代

Arrays 數組, ruby中允許使用負數索引[-1]...對於空內容,返回nil,
支持區間的訪問方式 a[1..3], 等同於a[1,3] 返回索引1到索引3之間的所有元素子數組
也內置了push,pop,shift等方法,用於模擬棧,隊列的行爲
對於搜索,可以使用fitst,last等方法,尋找指定的內容所在的索引

hash與array都提供了length,用於獲取長度
使用字典,判斷一個集合中出現的相同內容的次數...將每次的內容作爲key存入,然後對值進行+=1操作

繼承的使用,注意::前後都不允許有空格
class World < Test::Unit::TestCase

使用Blocks
some_array.each {|value| puts value * 3 } //each循環,可以用於數組和hashes, 注意block中參數設置
也可以使用do..end方式的block定義
other_array.each do |value|
sum += value
puts value / sum
end

注意block中變量的作用域問題,儘量不要在block中使用同名的變量
在1.9中已經修復,但還是建議不要使用與外部方法同名的變量名

與Groovy,對於block的循環,也內置了inject,collect,each等方法

將數組,hash轉換成迭代器的方式
a = [ 1, 3, "cat" ]
h = { dog: "canine", fox: "lupine" }
enum_a = a.to_enum
enum_h = h.to_enum

訪問的時候,只要調用next方法即可
enum_a.next....

對於迭代器,多了一種循環的方式loop do...end,也可以使用loop{block}到頭
short_enum = [1, 2, 3].to_enum
long_enum = ('a'..'z').to_enum
loop do
puts "#{short_enum.next} #{
long_enum.next}"
end
block的方式
v=[13,54,67,32]
ev=v.to_enum
loop {p ev.next}

Enumerators 本身也是一個對象,同樣具有一些方法,如從新轉換成數組
字符串轉換成數組的方式
result = []
"cat".each_char.each_with_index {|item, index| result << [item, index] }
result # => [["c", 0], ["a", 1], ["t", 2]]

同樣可以使用block達到一個自動關閉文件的事務處理
class File
def self.open_and_process(*args)
f = File.open(*args)
yield f
f.close()
end
end

在方法的內部,使用常量 if block_given? 可以判斷是否附帶了block

將block作爲對象使用,在方法定義的參數中,使用&name,對傳入的block進行捕獲,然後可以賦值給變量使用
def pass_in_block(&action)
@stored_proc = action
end
調用的時候,使用@stored_proc.call(parameter)

另外一種聲明block的方式---lamba
bo = lambda { |param| puts "You called me with #{param}" }
調用的方式一樣使用call
bo.call 99

closure閉包的實現,使用方法中返回的lamba,達到閉包的效果
def n_times(thing)
lambda {|n| thing * n }
end
p1 = n_times(23)
p1.call(3) # => 69

ruby1.9中創建lamba新的方式
->params { ... } 格式
proc1 = ->arg { puts "In proc1 with #{arg}" }
調用的方式
proc1.call "ant" , 其中可以帶多個參數

在定義lamba,或者->時, 也可以定義多種不同的參數,包括*arg,可變數量參數,&block

Ruby中,使用< 來實現簡單的繼承,同Java一樣,類默認都繼承Object,在1.9中,修改爲BasicObject
對弗雷方法的調用,一樣使用super

在ruby中,引入module,用於提供一個命名空間的方式去保存一些對象(class,method)等
需要注意的是這裏的命名規則
module Model // 首字母大寫
VAB=1 // 定義model內的常量
requeire "model"//在被引用時,首字母需要小寫
Model::VAB,引用model中的常量
Model.metho()// 使用module內的方法

對於引入的class,require時,可以忽略大小寫,當時在使用時.就必須使用首字母大寫

module的使用比較特殊一些,用於將一種包裝好的對象,直接include進入方法,就可以直接在類的內部附帶了這些方法,有些類似Java的 static import,靜態導入
概念上使用混編的方式,爲類提供繼承之外的選擇,又區別與Java中的組合,更便利的組合了方法的使用,無需自己重新爲類添加方法體---完善了接口的工作

沒有經過測試,當可以使用module保存一個全局變量,供其他類中進行共享,如果需要進行區分,可以使用object_id,來實現唯一的操作
def state=(value)
State[object_id] = value
end

如果方法中出現了多個同名的方法,Ruby會有自己一套的策略
如果是繼承的父類中擁有多個方法,那個將會使用第一個繼承的類
如果是多個導入模塊之間存在重複命名的方法,那麼將會採用最後一個找到的方法


Numbers
Integer 整型內主要包含Fixnum,Bignum兩種類型的數字,當數字的大小超過Fixnum後,會自動進行轉換
其他類型還有Complex,Rational,Float,Numeric
常用的數字循環有
3.times { print "X " }
1.upto(5) {|i| print i, " " }
99.downto(95) {|i| print i, " " }
50.step(80, 5) {|i| print i, " " }

Strings
可以使用""或''進行聲明,使用的時候注意,\進行轉義,使用的方式與其他語言類似
#{} 用於在字符串中插入Ruby語句,可以是變量,也可以是方法,也包括全局 變量
"This is line #$." # => This is line 3

%Q{...},%Q!...!,%q/.../ 也都可以用於包含字符生成字符串,代替"",主要作用是免去\轉義,同樣可以在裏面使用#{}

同Python一樣,可以在文件頭部聲明#encoding: utf8 來指定編碼,使用str.encoding 得到指定字符的編碼

簡單的使用正則的方式
c="123 1231 23s68 1628"
ob=c.scan(/\d+/)

Range 區間.類似Python中的定義
常見的定義方式
1..9
'a'..'z'
可以使用to_a,to_enum等方法轉換成所需的類型

常見的一些方法使用
digits = 0..9
digits.include?(5) # => true
digits.min # => 0
digits.max # => 9
digits.reject {|i| i < 5 } # => [5, 6, 7, 8, 9]
digits.inject(:+) # => 45

可以通過定義兩個方法,來對自定義的類添加Range的特性
def <=>(other)
@value <=> other.value
end
def succ
PowerOfTwo.new(@value + @value)
end

也可以將Range作爲條件區間使用
while line = gets
puts line if line =~ /start/ .. line =~ /end/ ..//用於讀取中在指定區間之間的內容,類似< ,>的使用
end

Range也可以使用===來進行判斷對象是否保存在該區間內
(1..10) === 5 # => true ,對浮點一樣有效

..兩個點與...三個點定義的區分, ..包括了後面數的,而...不包括<=與<的區別

Regular Expressions 正則表達式的使用
在ruby中的正則使用,字符串或者正則都可以調用對付進行匹配
1:匹配方法
=~ 用於匹配字符,並返回符合的字符所在索引
2:替換方法
str.sub(/pattern/,"value") 類似replace方法,返回修改的內容,同樣不對原內容進行修改
gsub.. replaceAll的實現
如果需要直接修改原內容,可以使用帶!版本的sub方法
str.sub!(/i/, "*")
str.gsub!(/t/, "T")

三種創建正則的方式
/pattern/ , Regexp.new("pattern"),%r{mm/dd}

得到模式匹配的內容,
pattern.match("str")進行內容匹配,以數組的形式返回匹配結果

\h用於匹配hex字符
\s用於匹配一些空格,換行,製表符等

ruby下還提供了一些[:space:]類似的方法,對一些常見的規則進行了封裝.這裏忽略
ruby還提供了一種是用key的方式,將捕獲的內容直接生成變量
/(?<hour>\d\d):(?<min>\d\d)(..)/ =~ "12:50am" 類似以前的$1等方式,
讀取時候使用"Hour is #{hour}, minute #{min}"

$的讀取方式,對reg中的()分組進行讀取,當採用上面的方法會更簡單一些
/(\d\d):(\d\d)(..)/ =~ "12:50am" # => 0
"Hour is #$1, minute #$2" # => "Hour is 12, minute 50"

動態替換字符
1:使用sub配合{}閉包對匹配的結果進行處理,讓結果可以動態變化
a = "quick brown fox"
a.sub(/^./) {|match| match.upcase } # => "Quick brown fox"
a.gsub(/[aeiou]/) {|vowel| vowel.upcase } # => "qUIck brOwn fOx"

2:使用&;方法,快速處理結果
name.downcase.gsub(/\b\w/, &:upcase)

3:使用hash方式,使用key-value,對匹配的字符進行處理,注意默認值的使用
replacement = { "cat" => "feline", "dog" => "canine" }
replacement.default = "unknown"
"cat and dog".gsub(/\w+/, replacement) # => "feline unknown canine"

對匹配的字符,使用\index的引用方式,索引由1開始
也可以\k<name>的方式進行讀取,同使用\?<>方式一樣

非捕獲分組
(?:....) ,這樣就不會保存該分組結果

匹配規則強化...
後匹配 (?=...) 表示其中的內容必須存在,當不捕獲
前匹配(?<=...)後面內容必須存在

(?!O) // 設置爲非捕獲排除O
(?>O) //進行嚴格匹配的設置,不截取部分 也可以寫成(O++)
控制回溯
用於控制懶惰和貪婪的搜索模式,默認爲貪婪,可以通過設置(?>),設置爲懶惰

其他太麻煩...不做記錄

More About Methods
Ruby中比較特殊的方式,使用?,=,!在方法名後進行了定義

當方法返回一個Boolean值時,常用?在結尾進行聲明
當方法可能造成危險時,常用!在結尾進行聲明
當方法設置值的時候,使用=進行聲明

如同Python一樣,也可以給方法的參數設置默認值
def method(arg="orz"...)
也可以通過第一個參數,動態生成第二個參數的默認值
def surround(word, pad_width=word.length/2)

可變參數列表
def varargs(arg1, *rest) //同Python一樣,Java中定義的方式 type...args
也可以直接使用(*)設置可變參數

對於處於參數列表中間的*,也會按照參數長度進行自動匹配....

ruby中的方法調用,並不要求()的使用, 同Python一樣,不需要使用return,即可對方法返回參數,
使用return時,可以用於返回多個結果

進行參數傳遞時,使用method(*(a),b) 其中的*()用於將裏面的參數自動拆轉成所需的參數列表值

Expressions 表達式
因爲Ruby是完全面向對象,所以與Java區別,沒有基本類型的限制,其基本類型也是對象,同樣提供了多種方法

可以通過重載運算符,爲自定義類添加便捷的操作方式
def <<(score)
@total_score += score
@count += 1
self //返回本身
end
甚至可以擴展方法名爲[],爲對象添加類似數組的方式,其實是一個方法調用
def [](p1, p2, p3)
end
如果要實現任意多個參數,注意使用*
def []=(*params)
end

Ruby中存在不少語法糖的用法
a = 1, 2, 3, 4 # a=[1, 2, 3, 4]
c, = 1, 2, 3, 4 # c=1
a, *b = 1, 2, 3 # a=1, b=[2, 3]
a, (b,*c), d = 1,[2,3,4],5 # a=1, b=2, c=[3, 4], d=5

注意ruby中不存在Java中的++操作,可以使用+=替換,在進行方法重載是也是

與Javascript類似,ruby中將nil都可以當做false使用,而非空的都當做true,
同樣也可以使用&& , || 對兩個值進行選擇

defined? 用於返回後面所帶參數的類型

可以在自定義類中重載==方法用於進行比較, 同樣也可以擴展!=方法
def ==(other)
end

ruby中的if...then..eleif...then...else 就是多了then,可以在一行中進行操作
比起Java,ruby中可以使用unless...進行if的反操作

switch的代替
case
when song.name == "Misty"
puts "Not again!"
when song.duration > 120
puts "Too long!"
when Time.now.hour > 21
puts "It's too late"
else
song.play
end

Loops循環
while 循環與Java一致
until 循環與while反作用

Iterators 迭代 多用於與block組合使用
3.times //...
0.upto(9) //..
0.step(12, 3) // 0-12 每次前進3
[ 1, 1, 2, 3, 5 ].each{} //迭代
執行文件操作時,可以使用File.open("ordinal").grep{...} 進行迭代

與Java中的類似,可以使用for...in的循環方式
for obj in array
...
end
也可以使用
array.each do |song|
song.play
end

可以通過在自定類中重載each方法來實現自定義循環方式

loop {} 循環 ,需要使用break跳出循環
Break, Redo, and Next 的使用
與Java相比,應該就是多了一個Redo

異常處理

完整的異常監聽
require 'openuri'
page = "podcasts"
file_name = "#{page}.html"
web_page = open("http://pragprog.com/#{page}")
output = File.open(file_name, "w")
begin //開始監聽
while line = web_page.gets
output.puts line
end
output.close
rescue Exception //catch異常
STDERR.puts "Failed to download #{page}: #{$!}"
output.close
File.delete(file_name)
raise //再次拋出異常
end

簡單的方式
begin
eval string
rescue SyntaxError, NameError => boom //同時捕獲多個異常,並進行重命名對象
print "String doesn't compile: " + boom
rescue StandardError => bang
print "Error running script: " + bang
ensure //類似finally
f.close
end

retry 可以用於在異常後,重新執行begin內的語句

raise ... 用於拋出異常,與throw一樣

異常捕獲的另外一種形式
catch(:done) do......的使用 將可能發生的異常封裝在變量內進行返回,內容可以通過throw 進行拋出
word_list = File.open("wordlist")
word_in_error = catch(:done) do
result = []
while line = word_list.gets
word = line.chomp
throw(:done, word) unless word =~ /^\w+$/
result << word
end
puts result.reverse
end
if word_in_error
puts "Failed: '#{word_in_error}' found, but a word was expected"
end

也可以使用throw :arg 進行一個異常信息的拋出

Basic Input and Output IO操作
使用File對象進行對本地文件的操作
File.open("testfile", "r") {} 使用block可以達到自動關閉的效果
File.new() 可以用於創建新文件

讀取文件操作
File.open("testfile") do |file|
while line = file.gets
puts line
end
end

也可以使用靜態的IO方法進行讀取
IO.foreach("testfile") {|line| puts line }
也可以按照數組的方式進行讀取
arr = IO.readlines("testfile")
arr.length # => 4
arr[0] # => "This is line one\n"

如果要寫入文件,需要在打開文件的參數中附加上"w"權限
File.open("output.txt", "w") do |file|
file.puts "Hello"
file.puts "1 + 2 = #{1+2}" //寫入
end
puts File.read("output.txt") //讀取
也可以使用<< 的方式將內容寫入文件

Talking to Networks 與網絡進行IO操作

Socket操作
require 'socket'
client = TCPSocket.open('127.0.0.1', 'finger')
client.send("mysql\n", 0) # 0 means standard packet
puts client.readlines
client.close

更高級的Http連接
require 'net/http'
h = Net::HTTP.new('www.pragprog.com', 80)
response = h.get('/titles/ruby3/programmingruby3')
if response.message == "OK"
puts response.body.scan(/<img alt=".*?" src="(.*?)"/m).uniq
end

也可以使用open-uri類庫
require 'openuri'
open('http://pragprog.com') do |f|
puts f.read.scan(/<img alt=".*?" src="(.*?)"/m).uniq
end
會自動對url不同進行處理


Fibers, Threads,and Processes

Fiber 在ruby1.9中新增纖程

Fiber 用於將元素保存在一個臨時的Fiber中,然後進行返回
words = Fiber.new {
Fiber.yield word.downcase
}
讀取的時候.使用resume方法 返回源對象
讀取的時候使用類似迭代的對象進行讀取操作
更完整的解釋應該是,將對象放入指定小線程中執行,使用resume得到結果 (異步)

創建多線程的方式
Thread.new(args){block} 的方式創建新的線程 ,返回線程對象
可以使用該對象的join進入該線程,也可以是執行該線程

sleep(rand(0.1)) 用於在線程體中進行休眠, rand用於生成0-1之間的小數

Thread.abort_on_exception = true 用於在執行線程時,忽略異常處理

Ruby中同步的方式
mutex.lock #### 鎖定線程
sum = inc(sum) # one at a time, please
mutex.unlock ####

也可以使用block的方式,自動解鎖
mutex.synchronize do ####
sum = inc(sum) # one at a time, please
end ####

Mutex.new本身也是對象,需要新建後使用,還提供了sleep等方法

Unit Testing

簡單的創建一個單元測試類
require 'test/unit'
class TestRoman < MiniTest::Unit::TestCase
def test_simple
assert_equal("i", Roman.new(1).to_s)
assert_equal("ix", Roman.new(9).to_s)
end
end

也可以繼承Test模塊
class TestRoman < Test::Unit::TestCase

注意命名規則
Test作爲類名開頭
test_作爲方法開頭

可以使用 require 'dbi 進行包含數據庫連接的測試

對於Class中定義的SRT=xx 這樣的變量, 可以在外部使用Class::SRT進行訪問, 類似Java中的靜態變量

:: 也可以用於訪問Module中的Class類型,然後進行實例化使用

設置源代碼 編碼
# coding: utf8 或# encoding: ascii

對字符進行編碼轉換
str= ole_str_utf.encode("iso88591")
在打開文件時,也可以通過附帶參數,使用指定編碼訪問文件
f = File.open("iso88591.txt", "r:iso88591")
也可以組合使用讀取,和輸出使用不同的編碼
f = File.open("iso88591.txt", "r:iso88591:utf8")
the first is the external encoding, and the second is the internal encoding.

讀取二進制文件的方法
f = File.open("iso88591.txt", "rb")

使用cgi.rb 可以搭建基於CGI的網絡應用

Haml and erb/eruby, 用於生成HTML的模板
如果需要生成XHTML或者xml,可以使用Builder

Haml更多的使用在內嵌的代碼中生成HTML
erb,更多的使用模板文件進行生成文件,當然也可以嵌入使用

Ruby and Microsoft Windows

Ruby提供了豐富的操作Windows Api的類庫
如 使用Email打開指定網頁
require 'win32ole'
ie = WIN32OLE.new('InternetExplorer.Application')
ie.visible = true
ie.navigate("http://www.pragprog.com")

生成新的Excel文件
excel = WIN32OLE.new("excel.application")

Ruby中包含了一些變量,用於保存特定情況下的信息
$! 異常信息
$@ 異常拋出的堆棧信息

names = %{ant bee cat}
result = names.map(&:upcase)
這裏的&:使用比較特殊,需要研究一下,現在運行出錯

在Ruby的class中提供了self對象,作用與Java中的this類似

定義靜態方法的方式,在定義方法名時,使用self.MethodName, 或 ClassName.MethodName進行定義
調用就可以直接使用ClassName.methodname進行直接調用

其他的方式訪問單例對象 ,定義類時
classname="" // 必須定義一個字符串 ,這樣在類中使用self時,就會變成這裏的賦值
class << className ,這樣內部的方法就可以直接使用class調用

<<定義類的方式應用比較多一些,也可以作爲變量返回.也可以用於暴露出特定的變量提供使用Class進行修改(亂)
class Test
@var = 99
class << self
attr_accessor :var
end
end
這樣就可以通過Test.var對實例變量進行修改

在Ruby中可以通過在子類中,修改父類的方法訪問級別,將private的方法變成public的方法
其實就是通過重載方法,然後在子類中調用super //這裏也比Java簡單了,直接在方法體中調用super,就可以執行父類中的同名方法

對模塊的繼承 extend
module Humor
def tickle
"#{self} says hee, hee!"
end
end
obj = "Grouchy"
obj.extend Humor
puts obj.tickle

也可以在類中使用
class Grouchy
extend Humor
end
puts Grouchy.tickle

include主要用來將一個模塊插入(mix)到一個類或者其它模塊。
extend 用來在一個對象(object,或者說是instance)中引入一個模塊,這個類從而也具備了這個模塊的方法。

使用的三種情況
在類中include模塊,使模塊中的方法成爲類的實例方法
在類定義中extend模塊,使模塊中的方法成爲類的類方法
實例方法和類方法的區別,就如同非靜態方法,與靜態方法的區別

Struct, 類似c中的struct, 可以用於便捷的創建class級別對象,
Person = Struct.new(:name, :address, :likes) //參數中的應該是實例變量,也可以作爲構造函數動態傳入
dave = Person.new('Dave', 'TX')
dave.likes = "Programming Languages"
puts dave

重寫該類中的方法
Person = Struct.new(:name, :address, :likes)
class Person
def to_s
"#{self.name} lives in #{self.address} and likes #{self.likes}"
end
end

也可以寫成另外中形式,更利於閱讀一些
class Person < Struct.new(:name, :address, :likes)
def to_s
"#{self.name} lives in #{self.address} and likes #{self.likes}"
end
end

動態的創建類的另外一種方式,可以使用block對類的方法進行定義
some_class = Class.new do
def self.class_method
puts "In class method"
end
def instance_method
puts "In instance method"
end
end
some_class.class_method
obj = some_class.new
obj.instance_method

instance_eval and class_eval 也可以用動態創建類
"cat".instance_eval do //使用block的方式
puts "Upper case = #{upcase}"
puts "Length is #{self.length}"
end

也可以使用參數傳遞的方式
"cat".instance_eval('puts "Upper=#{upcase}, length=#{self.length}"')

class_evel的使用,爲已存在的類添加實例方法
class MyClass
end
MyClass.class_eval do
def instance_method
puts "In an instance method"
end
end

而對已存在的class調用instance_eval,而是添加類方法,也是使用block進行傳遞

可以在Ruby的class類中,實現一些Hook方法,用於在類調用時,發生的一些事件進行回調,如果方法未定義,參數錯誤等
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章