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的静态作用域中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Programming Ruby 第二版(Second Edition)英文版于2005年出版,之后有了中文版。但可惜的是网上流传的中文版PDF基本上都是扫描版的,文字内容得自己打出来,看到好的代码也得自己动手,无法Ctrl-C + Ctrl-V,还不如看英文版的非扫描版。于是我就想到发布英文非扫描版的Programming Ruby Second Edition(与Ruby1.8结合),希望各位同学有所收获…… 以下摘录部分内容: From Page 305 Strings Ruby provides a number of mechanisms for creating literal strings. Each generates objects of type String. The different mechanisms vary in terms of how a string is delimited and how much substitution is done on the literal’s content. Single-quoted string literals ('stuff ' and %q/stuff /) undergo the least substitution. Both convert the sequence \\ into a single backslash, and the form with single quotes converts \' into a single quote. All other backslashes appear literally in the string. 'hello' ! hello 'a backslash \'\\\'' ! a backslash '\' %q/simple string/ ! simple string %q(nesting (really) works) ! nesting (really) works %q no_blanks_here ; ! no_blanks_here Double-quoted strings ("stuff ", %Q/stuff /, and %/stuff /) undergo additional substitutions, shown in Table 22.2 on the next page. a = 123 "\123mile" ! Smile "Say \"Hello\"" ! Say "Hello" %Q!"I said 'nuts'," I said! ! "I said 'nuts'," I said %Q{Try #{a + 1}, not #{a 1}} ! Try 124, not 122 % ! Try 124, not 122 "Try #{a + 1}, not #{a 1}" ! Try 124, not 122 %{ #{ a = 1; b = 2; a + b } } ! 3 Strings can continue acrossmultiple input lines, in which case they will contain newline characters. It is also possible to use here documents to express long string literals. Whenever Ruby parses the sequence <<identifier or <<quoted string, it replaces it with Prepared exclusively

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值