programming ruby

Day one

方法时通过向对象发送消息来唤起调用的。

而ruby里,确定绝对值的能力是内建在数字中——处理细节在内部实现中。只要发送abs消息到一个数字对象,让它去得到绝对值即可。

number = number.abs

result变量不必声明;当赋值给它的时候,它便存在了

ruby里面不用{}包含方法体,它使用end来包含

调用参数可以放到括号里 也可以不放在括号里 看个人喜好

但是除了最简单的情况下,请使用括号。

ruby对双引号字符串有更多的处理。首先,它寻找以反斜线开始的序列,并用二进制值替换它们。其中最常见的是\n,他会被回车换行符替换掉。

“”中的#{表达式}会被表达式的值替换掉。

ruby方法的返回值是最后一个计算的结果

局部变量、方法参数和方法名称都必须以小写字母或下划线开始。全局变量都有美元符号$为前缀,而实力变量也@符号开始。类变量以@@符号开始。类名称、模块名称和常量都以一个大写字母开始。


[img]http://dl.iteye.com/upload/attachment/0083/4243/65377b39-1b83-3f85-9eb1-43178134e7b9.jpg[/img]


Day Two

%w可以创建字符串数组,比普通的创建优点是不用写""了。

a = %w[ant bee cat]
a[0] -> "ant"


散列:

inst_section = {
'cello' => 'string',
'clarinet' => 'woodwind'
}


散列的key不能一样 inst_section['cello'] -> 'string'

没有key的时候返回nil,在if判断里面nil代表false,如果你想让返回一个默认值的时候可以这样写:

histogram = Hash.new(0)

这样默认返回的就是0

如果if和while程序体只有一个表达式,Ruby的语句修饰符是一种有用的快捷方式。

puts "test" if radiation > 3000

正则表达式:

if line =~ /Perl|Python/
puts "Scripting language mentioned: #{line}"
end

替换:

line.sub(/Perl/, 'ruby') 替换第一个Perl
line.gsub(/Perl/, 'ruby') 替换所有


Block例子:

def call_block
puts "Start of method"
yield
yield
puts "End of method"
end

call_block { puts "In the block" }


produces:
Start of method
In the block
In the block
End of method

同理可以为Block传递参数:

def call_block
yield("hello", 99)
end

call_block {|str, num| ... }


原来下面的都是Block

[ 'cat', 'dog', 'horse' ].each {|name| print name, " " }
5.times { print "*" }
3.upto(6) {|i| print i }
('a'..'e').each {|char| print char }



属性的读取:

class Song
def name
@name
end
def artist
@artist
end
def duration
@duration
end
end
song = Song.new("Bicylops", "Fleck", 260)
song.artist ! "Fleck"
song.name ! "Bicylops"
song.duration ! 260



可以简写为:

class Song
attr_reader :name, :artist, :duration
end


attr_reader其实是Ruby的一个方法,而:name等符号是其参数。它会通过代码求解动态地在Song类中加入势力方法体。

构成体:artist是一个表达式,它返回对于artist的一个Symbol对象。你可以将:artist看做是变量artist的名字,而普通的artist是变量的值。

写方法:

class Song
attr_writer :duration
end



定义类方法:

class Example
def instance_method # instance method
end
def Example.class_method # class method
end
end


创建数组:

a = [1,2,3]

或者

a = Array.new

使用负数索引,就是从后往前找

a = [1,2,3,4,5,6,7,8,9]

a[-1] -> 9

[start, count]

a[1,3] -> [2,3,4]

使用range索引,start end 不是个数

a[1..4] -> [2,3,4,5]

3个.代表不包含后面的那个

散列:

h = {'dog' => 'canine', 'cat' => 'feline'}

collect它所做的就是连续访问收集的所有元素

[1,3,4,5,6].collect {|x| x = x+1} -> [2,4,5,6,7]

inject方法让你可以遍历收集的所有成员以累计出一个值。

[1,3,5,7].inject(0) {|sum, element| sum+element} → 16 
[1,3,5,7].inject(1) {|product, element| product*element} → 105


读取数据流:

File.open_and_process("testfile", "r") do |file|
while line = file.gets
puts line
end end


Blocks可以作为闭包

 songlist = SongList.new
class JukeboxButton < Button
def initialize(label, &action) super(label)
@action = action
end
def button_pressed
@action.call(self)
end end
start_button = JukeboxButton.new("Start") { songlist.start } pause_button = JukeboxButton.new("Pause") { songlist.pause }


注意&的参数,当调用该方法的时候,Ruby会寻找一个block。block将会被转化成Proc类的一个对象,并赋值给参数。我们可以Proc#call方法去调用相应的block。

block上下文也会得到,self的值、作用域内的方法、变量和常熟。例子:

该例子使用了lambda方法,该方法将一个block转换成了Proc对象。

 def n_times(thing)
return lambda {|n| thing * n }
end
p1 = n_times(23)
p1.call(3) → 69
p1.call(4) → 92
p2 = n_times("Hello ")
p2.call(3) → "Hello Hello Hello "


正则表达式:

正则表达式是Regexp类型的对象。可以通过显示地调用构造函数活使用字面量形式/pattern/和%r{pattern}来创建它们

a = Regexp.new('^\s*[a-z]')
b = /^\s*[a-z]/
c = %r{^\s*[a-z]} → /^\s*[a-z]/ → /^\s*[a-z]/ → /^\s*[a-z]/


一旦有了正则表达式对象,可以使用Regexp#match(string)或匹配操作符=~(肯定匹配)和!~(否定匹配)对字符串进行匹配。

name = "Fats Waller" 
name=~/a/ → 1
name =~ /z/ → nil
/a/=~name → 1


定义一个方法:

表示查询的方法名通常以?结尾。危险的或者会修改接受者对象的方法,可以用!结尾,可以赋值的方法以一个等号=结尾。只有?!=这几个怪异的字符能够作为方法名的后缀。

方法名的参数,我们的惯例是有参数用括号 没有参数不用括号

可以给方法设置默认值:

def cool_dude(arg1="Miles", arg2="Coltrane", arg3="Roach") "#{arg1}, #{arg2}, #{arg3}."
end
cool_dude -> "Miles, Coltrane, Roach."
cool_dude("Bart") -> "Bart, Coltrane, Roach."
cool_dude("Bart", "Elwood") -> "Bart", "Elwood, Roach."
cool_dude("Bart", "Elwood", "Linus") → "Bart, Elwood, Linus."


可变长度的参数列表

def varargs(arg1, *rest)
 "Got #{arg1} and #{rest.join(', ')}"
end

varargs("one")
varargs("one","two") → "Got one and two"
varargs "one","two", "three" → "Got one and two, three"

第一个参数赋值给方法的第一个参数。不过,第二个形参的前缀为星号,因此所有剩余的参数被装入到一个新的array中,然后赋值给第二个形参。

如果你给return多个参数,方法就会将它们以数组的形式返回。你可以使用并行赋值来收集返回值。

num, square = meh_three

def five(a, b, c, d, e)
"I was passed #{a} #{b} #{c} #{d} #{e}"
end
five(1,2,3,4,5)
five(1, 2, 3, *['a', 'b'])
five(*(10..14).to_a)

→ "Iwaspassed12345"
→ "I was passed 1 2 3 a b"
→ "Iwaspassed1011121314"


将block从if else中抽取出来:

  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


重构之后的代码,就是抽出一个代码快:

print "(t)imes or (p)lus: "
times = gets
print "number: "
number = Integer(gets)
if times =~ /^t/
calc = lambda {|n| n*number }
else
calc = lambda {|n| n+number }
end
puts((1..10).collect(&calc).join(", "))


如果方法的最后一个参数前有一个&符号,Ruby将认为它是一个Proc对象。它会将其从参数列表中删除,并将Proc对象转换为一个block,然后关联到该方法。

并行赋值:

交换两个值:

a, b = b, a

Ruby的赋值实际是以并行方式执行的,所以赋值语句右边的值不受赋值语句本书的影响,在左边的任意一个变量活属性被赋值之前,右边的值按它们出现的顺序被计算出来。

数字0不被解释为假值,长度为0的字符串也不是假值。

3.times do
print "a"
end

0.upto(9) do |x|
print x, " "
end

步长为3:
0.step(12, 3) {|x| print x, " " }

File.open("ordinal").grep(/d$/) do |line| puts line
end

取出符合条件的行

内建的loop的迭代器:

loop do

end

loop循环一直执行给定的块或者知道你跳出循环。

songlist.each do |song|
song.play
end


break不解释,next不解释同continue。redo从循环头重新执行循环,但不重计算循环条件表达式或者获得迭代的下一个元素。

可以传递一个值给break和next。在传统的循环中,这可能只对break有意义,此时break将设置循环的返回值。传递给next的人一直会被丢弃掉。

result = while line = gets
break(line) if line =~ /answer/
end process_answer(result) if result


[color=red]while until 和 for 循环内建在Ruby语言中,但没有引入新的作用域:前面已经存在的局部变量可以在循环中使用。而循环中新创建的局部变量也可以在循环后使用。

被迭代器使用的block(比如loop和each)与此略有不同。通常,在这些block中创建的局部变量无法在block外访问。[/color]

在一个begin/end块中,使用一个或者多个rescue余怒告诉Ruby希望处理的异常类型。

op_file = File.open(opfile_name, "w")
begin
# Exceptions raised by this code will
# be caught by the following rescue clause
while data = socket.read(512)
op_file.write(data)
end
rescue SystemCallError
$stderr.print "IO failed: " + $!
op_file.close
File.delete(opfile_name)
raise
end


当异常被引发时,Ruby将相关Exception对象的引用放在全局变量$!中,这与任何随后的异常处理不相干。


[img]http://dl.iteye.com/upload/attachment/0083/5431/4487ce82-7f17-3d6a-bb9c-6964a021ede8.jpg[/img]

关闭和删除文件后,我们可以不带任何参数来调用raise,它会重新引发$!中的异常。这是一个有用的技术,它允许我们先编写代码过滤掉一些异常,再把不能处理的异常传递到更高的层次。这几乎就像实现了一个错误处理的继承层次结构。

在begin块中可以有多个rescue子句,每个rescue子句可以指示捕获多个异常。在rescue子句的结束处,你可以提供一个Ruby的局部变量名来接受匹配的异常。

begin
eval string
rescue SyntaxError, NameError => boom
print "String doesn't compile: " + boom
rescue StandardError => bang
print "Error running script: " + bang
end


如果编写一个不带参数表的rescue子句,它的默认参数是StandardError

ensure相当于java里的finally:

f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end


尽管不那么有用,else子句是一个类似ensure子句的构造。如果存在的话,它会存现在rescue子句之后和任何一个ensure子句之前。else子句的程序体,只有当主代码没有引发任何异常时才会被执行。

f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
else
puts "Congratulations no errors!"
ensure
f.close unless f.nil?
end


引发异常:

raise
raise "bad mp3 encoding"
raise InterfaceException, "Keyboard failure", caller

第一种形式只是简单滴重复引发当前异常(如果没有当前异常的话,引发RuntimeError)。这种形式用于首先截获异常再将其继续传递的异常处理方法中。

第二种形式创建新的RuntimeError异常,把它的消息设置为指定的字符串。然后异常随着调用栈向上引发。

第三种形式使用第一个参数创建异常,然后把相关联的消息设置给第二个参数,同时吧栈信息设置给第三个参数。通常,第一个参数是Exception层次结构中某个类的名称,或者是某个异常类的对象实例引用。通常使用Kernel.caller方法产生栈信息。

典型的一个例子:

raise
raise "Missing name" if name.nil?
if i >= names.size
raise IndexError, "#{i} >= size (#{names.size})"
end
raise ArgumentError, "Name too big", caller


创建自己的异常:

class RetryException < RuntimeError
attr :ok_to_retry
def initialize(ok_to_retry)
@ok_to_retry = ok_to_retry
end
end


使用方法:

def read_data(socket)
data = socket.read(512)
if data.nil?
raise RetryException.new(true), "transient read error"
end
# .. normal processing
end

begin
stuff = read_data(socket)
# .. process stuff
rescue RetryException => detail
retry if detail.ok_to_retry
raise
end


尽管raise和rescue的异常机制对程序出错时终止执行已经够用了,但是如果在正常处理期间能够从一些深度嵌套的结构中跳转出来,则是很棒的。

catch (:done) do
while line = gets
throw :done unless fields = line.split(/\t/)
songlist.add(Song.new(*fields))
end
songlist.play
end


catch定义了以给定名称为标签的block。这个block会正常执行知道遇到throw为止。

当Ruby碰到throw,它迅速回溯调用栈,用匹配的符号寻找catch代码块。当发现它之后,Ruby将栈清退到这个位置并终止该block,所以在前面的例子中,如果输入没有包含正确格式化的行,throw会跳到相应catch代码块的结束处,不仅终止了while循环,而且跳过了歌曲列表的播放。如果调用throw时指定了可选的第二个参数,这个值会作为catch的值返回。

def prompt_and_get(prompt)
print prompt
res = readline.chomp
throw :quit_requested if res == "!"
res
end
catch :quit_requested do
name = prompt_and_get("Name: ")
age = prompt_and_get("Age: ")
sex = prompt_and_get("Sex: ")
# ..
# process information
end


这个例子说明了throw没有必要出现在catch的静态作用域中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值