Ruby基础
开始
查看当前ruby的版本号,最新的版本是1.9:
>%ruby -v
ruby 1.9.0 (2006-06-08) [i486-linux]
交互式ruby:
ruby方式:
>%ruby
print "hello world"
^D #Ctrl+D结束当前语句,显示结果并退回shell
hello world
irb方式:
>irb(main):001:0> print "hello world"
hello world=> nil
irb(main):002:0> exit
#注意最后一条语句不能出现;否则irb会让你继续输入
irb(main):002:0> print "hello world"; #此处有;号
irb(main):003:0* print "demy" #irb会让你继续输入,认为是多条语句
hello worldok=> nil
irb(main):004:0> exit #exit退出
###另一个例子
irb(main):001:0> def sum(n1,n2)
irb(main):002:1> n1+n2
irb(main):003:1> end
=> nil
irb(main):004:0> sum(3,4)
=> 7
irb(main):005:0> sum("cat","dog")
=> "catdog"
###导入外部文件
% irb
irb(main):001:0> load "code/rdoc/fib_example.rb"
=> true
irb(main):002:0> Fibonacci.upto(20)
=> [1, 1, 2, 3, 5, 8, 13]
也可以通过ruby -e来制定语句,和perl,sed这些一样,后面跟ruby语句
>%ruby -e "print 'hello world'"
hello world
ruby程序:
>%ruby test.rb
Hello World
%cat test.rb
#!/usr/bin/ruby -w
puts "Hello World"
#或者用./test.rb
ruby文档:RDoc和ri
如果ruby的源文件是用RDoc生成的,那么文档则可以被转换成html和ri格式。
>#寻找一个类的文档,使用ri+类名的格式
%ri GC
Class:
GC
The GC module provides an interface to Rubys mark and sweep
garbage collection mechanism. Some of the underlying methods are
also available via the ObjectSpace module.
Class
methods:
disable, enable, start
Instance methods:
garbage_collect
#寻找方法的文档
% ri start
More than one method matched your request. You can refine
your search by asking for information on one of:
Date#new_start, Date#start, GC::start, Logger::Application#start,
Thread::start
#指定类名和方法
% ri GC.start
GC::
start
GC.start => nil
gc.garbage_collect => nil
ObjectSpace.garbage_collect => nil
Initiates
garbage collection, unless manually disabled.
设置ri的显示模式:
>% export RI="format ansi width 70"
Ruby.new
ruby是一种面向对象的语言
在ruby中,对象是由构造器构造,标准的构造方法是new
>song1 = Song.new("Ruby Tuesday")
song2 = Song.new("Enveloped in Python")
# and so on
ruby是完全OO的,可以和其他语言进行比较
>number = Math.abs(number) // Java code
number = number.abs
Ruby基础
以一个简单的ruby程序开始:
>def say_goodnight(name)
result = "Good night, " + name
return result
end
# Time for bed...
puts say_goodnight("JohnBoy")
puts say_goodnight("MaryEllen")
字符串内的表达式内插:
>def say_goodnight(name)
result = "Good night, #{name}" # #{}是固定模式,也可以跟方法#{name.capitalize}
return result
end
puts say_goodnight('Pa')
结果:
Good night, Pa
当#{}里面的值只是全局,实例或者类的变量的话,不需要{}
>$greeting = "Hello" # $greeting 代表全局变量
@name = "Prudence" # @name 是实例变量
puts "#$greeting, #@name"
结果:
Hello, Prudence
数组和Hash:
>a = [ 1, 'cat', 3.14 ] # 包含3个元素的数组
# access the first element
a[0]->1
# 设置第3个元素的值
a[2] = nil
a->[1, "cat", nil]
变量类型:
局部 | 全局 | 实例(类属性) | 类(static) | 常量 |
name | $debug | @name | @@total | PI |
fish_and_chips | $CUSTOMER | @point_1 | @@symtab | FeetPerMile |
x_axis | $_ @X | @@N | String | |
thx1138 | $plan9 | @_ | @@x_pos | MyClass |
_26 | $Global | @plan9 | @@SINGLE | JazzSong |
有的时候创建数组可能会麻烦因为包含了引号和逗号,在ruby中可以用%w来构建数组:
>a = [ 'ant', 'bee', 'cat', 'dog', 'elk' ]
a[0] ! "ant"
a[3] ! "dog"
#下面的一样
a = %w{ ant bee cat dog elk }
a[0] -> "ant"
a[3] -> "dog"
Hash的构造和Perl一样:
>inst_section = {
'cello' => 'string',
'clarinet' => 'woodwind',
'drum' => 'percussion',
'oboe' => 'woodwind',
'trumpet' => 'brass',
'violin' => 'string'
}
Hash中元素的访问:
>inst_section['oboe'] ->"woodwind"
inst_section['cello'] -> "string"
inst_section['bassoon'] -> nil
下面这个例子示范了,一个hash返回nil当key不存在时,但是hash也可以指定当key不存在时的值,通过new来构造hash
>histogram = Hash.new(0)
histogram['key1'] -> 0
histogram['key1'] = histogram['key1'] + 1
histogram['key1'] -> 1
控制结构:
>#if语句
if count > 10
puts "Try again"
elsif tries == 3
puts "You lose"
else
puts "Enter a number"
end
#while语句
while weight < 100 and num_pallets <= 30
pallet = next_pallet()
weight += pallet.weight
num_pallets += 1
end
while line = gets
puts line.downcase
end
square = 2
while square < 1000
square = square*square
end
#简洁模式,和perl有些类似
puts "Danger, Will Robinson" if radiation > 3000
square = 2
square = square*square while square < 1000
正则表达式:
>if line =~ /Perl|Python/
puts "Scripting language mentioned: #{line}"
end
line.sub(/Perl/, 'Ruby') # 将第一个'Perl'替换成'Ruby'
line.gsub(/Python/, 'Ruby') # 替换所有'Python'成'Rub
语句块和迭代器
>{ puts "Hello" } # 这是语句块
do ###
club.enroll(person) #这也是一个语句块
person.socialize #
end
当你创建了一个语句块后,你可以通过一个方法来绑定它。通过将语句块的开始放在包含方法后面
>def greet
puts "greet"
end
greet { puts "Hi" } #语句块和greet方法绑定
->greet #默认并不会附加语句块的结果
verbose_greet("Dave", "loyal customer") { puts "Hi" } #如果方法有参数
如果需要用到绑定的语句块,需要通过yield的关键字
>def call_block
puts "Start of method"
yield
yield
puts "End of method"
end
call_block { puts "In the block" }
结果:
Start of method
In the block
In the block
End of method
你也可以给yield设定参数
>def call_block
yield("hello", 99)
end
call_block {|str, num| ... }
通过iterator遍历数组
>animals = %w( ant bee cat dog elk ) # create an array
animals.each {|animal| puts animal } # iterate over the contents
[ 'cat', 'dog', 'horse' ].each {|name| print name, " " }
5.times { print "*" }
3.upto(6) {|i| print i }
('a'..'e').each {|char| print char }
读和写:
>printf("Number: %5.2f,/nString: %s/n", 1.23, "hello")
Number: 1.23,
String: hello
#读入用户输入
while gets
if /Ruby/
print
end
end
在以前ruby很多都借用了perl,读入用户输入可以这样
>while gets
if /Ruby/
print
end
end
但是不推荐,推荐用ruby的方式
>ARGF.each {|line| print line if line =~ /Ruby/ }
也可以更简洁
print ARGF.grep(/Ruby/)
类对象和变量
initialize是类中一个特殊的方法,构造方法
>class Song
def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
end
end
测试
>song = Song.new("Bicylops", "Fleck", 260)
song.inspect -> #<Song:0x1c7ca8 @name="Bicylops", @duration=260,
@artist="Fleck"
song = Song.new("Bicylops", "Fleck", 260)
song.to_s -> "#<Song:0x1c7ec4>" #Object ID
#重写 to_s方法
class Song
def to_s
"Song: #@name----#@artist (#@duration)"
end
end
song = Song.new("Bicylops", "Fleck", 260)
song.to_s -> "Song: BicylopsFleck
(260)"
继承和消息
>class KaraokeSong < Song
def initialize(name, artist, duration, lyrics)
super(name, artist, duration)
@lyrics = lyrics
end
end
<Song代表 KaraokeSong是Song的子类
对象和属性
访问对象的属性
>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
这种方式太繁琐,可以用attr_reader
>class Song
attr_reader :name, :artist, :duration
end
#后面的结果和前面的一样
虚拟属性
>class Song
def duration_in_minutes
@duration/60.0 # force floating point
end
def duration_in_minutes=(new_duration)
@duration = (new_duration*60).to_i
end
end
song = Song.new("Bicylops", "Fleck", 260)
song.duration_in_minutes -> 4.33333333333333
song.duration_in_minutes -> 4.2
song.duration -> 252
类变量
>class Song
@@plays = 0
def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
@plays = 0
end
def play
@plays += 1 # same as @plays = @plays + 1
@@plays += 1
"This song: #@plays plays. Total #@@plays plays."
end
end
类方法
>class Example
def instance_method # 实例方法
end
def Example.class_method # 类方法
end
end
类方法其实可以有多种方法
>class Demo
def Demo.meth1
# ...
end
def self.meth2
# ...
end
class <<self
def meth3
# ...
end
end
end
单例设计模式和其他
>class MyLogger
private_class_method :new
@@logger = nil
def MyLogger.create
@@logger = new unless @@logger
@@logger
end
end
访问控制
>class MyClass
def method1 # default is 'public'
#...
end
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 # and this will be 'public'
#...
end
end
#或者可以用列表的方法设定控制层级
class MyClass
def method1
end
# ... and so on
public :method1, :method4
protected :method2
private :method3
end
保护访问
>class Account
attr_reader :balance # accessor method 'balance'
protected :balance # and make it protected
def greater_balance_than(other)
return @balance > other.balance
end
end
变量
注意ruby里面变量并不是对象,只是对象的引用而已,下面的例子可以说明
>person1 = "Tim"
person2 = person1
person1[0] = 'J'
person1 -> "Jim"
person2 -> "Jim"
person1到person2的赋值并没有改变对象的值,只是拷贝person1这个引用到person2而已
改变这种方式可以用dup
>person1 = "Tim"
person2 = person1.dup
person1[0] = "J"
person1 -> "Jim"
person2 -> "Tim"
也可以保护某个特定的Object不被改变,这时使用freeze
>person1 = "Tim"
person2 = person1
person1.freeze # prevent modifications to the object
person2[0] = "J"
结果:
prog.rb:4:in `[]=': can't modify frozen string (TypeError) #报错误
from prog.rb:4
容器,语句块,迭代器
容器
数组
>a = [ 3.14159, "pie", 99 ]
a.class -> Array
a.length -> 3
a[0] -> 3.14159
b = Array.new
b.class -> Array
b.length -> 0
Array通过[]被索引
>a = [ 1, 3, 5, 7, 9 ]
a[1]->9
a[2]->7
a[99]->nil
也可以用[start,end]来索引,slice
>a = [ 1, 3, 5, 7, 9 ]
a[1, 3] -> [3, 5, 7]
a[3, 1] -> [7]
a[3,2] -> [5, 7]
可以更简洁
>a = [ 1, 3, 5, 7, 9 ]
a[1..3] -> [3, 5, 7]
a[1...3] -> [3, 5]
a[3..3] -> [7]
a[3..1] -> [5, 7, 9]
Hash
>h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' }
h.length -> 3
h['dog'] -> "canine
实现一个songlist
>class SongList
def initialize
@songs = Array.new
end
def append(song)
@songs.push(song)
self
end
def delete_first
@songs.shift
end
def delete_last
@songs.pop
end
def [](index)
@songs[index]
end
end
如果要实现songlist的with_title方法
>def with_title(title)
for i in 0...@songs.length
return @songs[i] if title == @songs[i].name
end
return nil
end
#可以更简洁,可以用find实现
class SongList
def with_title(title)
@songs.find {|song| title == song.name }
end
end
实现迭代器
yield的用法
>def three_times
yield
yield
yield
end
three_times { puts "Hello"}
def fib_up_to(max)
i1, i2 = 1, 1 # parallel assignment (i1 = 1 and i2 = 1)
while i1 <= max
yield i1
i1, i2 = i2, i1+i2
end
end
fib_up_to(1000) {|f| print f, " " }
遍历
>a = [1, 2]
b = 'cat'
a.each {|b| c = b * a[1] }
find实现方式
>class Array
def find
for i in 0...size
value = self[i]
return value if yield(value)
end
return nil
end
end
[1, 3, 5, 7, 9].find {|v| v*v > 30 } ! 7
另一个通常的iterator是collect,语句的结果用来构造来一个新的array
>["H", "A", "L"].collect {|x| x.succ } => ["I", "B", "M"]
再看一个更加有用的iterator,inject,inject让你从列表中计算某个值
>[1,3,5,7].inject(0) {|sum, element| sum+element} -> 16
[1,3,5,7].inject(1) {|product, element| product*element} -> 105
inject的工作的方式是这样,inject中的值赋值给sum,element被赋值给collection中的第一个值,第2次,block返回的值再赋值给sum,element取collection中第2个值,如此得到最后的值
注意:如果Inject没有参数的话,默认取collection的第一个数据做为参数,从collection第2个数据开始计算
>[1,3,5,7].inject {|sum, element| sum+element} -> 16
[1,3,5,7].inject {|product, element| product*element} -> 105
>class File
def File.open_and_process(*args)
f = File.open(*args)
yield f
f.close()
end
end
class File
def File.my_open(*args)
result = file = File.new(*args)
# If there's a block, pass in the file and close
# the file when it returns
if block_given?
result = yield file
file.close
end
return result
end
end
lambda表达式
>def n_times(thing)
return lambda {|n| thing * n }
end
>3.times { print "X " }
1.upto(5) {|i| print i, " " }
99.downto(95) {|i| print i, " " }
50.step(80, 5) {|i| print i, " " }
表达式内插可以支持复杂的语句
>puts "now is #{ def the(a)
'the ' + a
end
the('time')
} for all good coders..."
String的构造
>%q/general singlequoted
string/ -> general singlequoted
string
%Q!general doublequoted
string! -> general doublequoted
string
%Q{Seconds/day: #{24*60*60}} -> Seconds/day: 86400
通过heredocument构造String
>string = <<END_OF_STRING
The body of the string
is the input lines up to
one ending with the same
text that followed the '<<'
END_OF_STRING