link
w3cschool tutorial
简介
Ruby是一种完美的面向对象编程语言。面向对象编程语言的特性包括:
类
在 Ruby 中,类总是以关键字 class 开始,后跟类的名称。类名的首字母应该大写。类 Customer 如下所示:
class Customer
end
Ruby 类中的变量
- 局部变量:局部变量是在方法中定义的变量。局部变量在方法外是不可用的。在后续的章节中,您将看到有关方法的更多细节。局部变量以小写字母或 _ 开始。
- 实例变量:实例变量可以跨任何特定的实例或对象中的方法使用。这意味着,实例变量可以从对象到对象的改变。实例变量在变量名之前放置符号(@)。
- 类变量:类变量可以跨不同的对象使用。类变量属于类,且是类的一个属性。类变量在变量名之前放置符号(@@)。
- 全局变量:类变量不能跨类使用。如果您想要有一个可以跨类使用的变量,您需要定义全局变量。全局变量总是以美元符号($)开始。
(给全局变量赋值会改变全局状态,所以不建议使用全局变量)
Ruby 点运算符 “.” 和双冒号运算符 “::”
您可以通过在方法名称前加上模块名称和一条下划线来调用模块方法。您可以使用模块名称和两个冒号来引用一个常量。
:: 是一元运算符,允许在类或模块内定义常量、实例方法和类方法,可以从类或模块外的任何地方进行访问。
请记住:在 Ruby 中,类和方法也可以被当作常量。
您只需要在表达式的常量名前加上 :: 前缀,即可返回适当的类或模块对象。
如果未使用前缀表达式,则默认使用主 Object 类。
下面是两个实例:
1 2 3 4 5 6 7 8
| MR_COUNT = 0 # 定义在主 Object 类上的常量 module Foo MR_COUNT = 0 ::MR_COUNT = 1 # 设置全局计数为 1 MR_COUNT = 2 # 设置局部计数为 2 end puts MR_COUNT # 这是全局常量 puts Foo::MR_COUNT # 这是 "Foo" 的局部常量
|
修饰词
if
为真,执行后面
1 2 3 4 5 6 7 8
| x=1 if x > 2 puts "x is greater than 2" elsif x <= 2 and x!=0 puts "x is 1" else puts "I can't guess the number" end
|
unless 为假,执行后面
1 2 3 4 5 6
| x=1 unless x>2 puts "x is less than 2" else puts "x is greater than 2" end
|
case
1 2 3 4 5 6 7 8
| case expr0 when expr1, expr2 stmt1 when expr3, expr4 stmt2 else stmt3 end
|
while 为真,继续执行
1 2 3 4 5 6
| i = 0 while $i < 5 do puts("Inside the loop i = #i" ) i +=1 end
|
修饰符在后的用法
当 conditional 为真时,执行 code。
1 2 3 4 5 6 7
| code while condition 或者 begin code end while conditional
|
until 为假,继续执行
= 11 2 3 4 5
| until x > 4 puts x x += 1 end
|
for
1 2 3
| for i in 0..5 puts "Value of local variable is #{i}" end
|
for…in 循环几乎是完全等价于:
1
| (expression).each do |variable[, variable...]| code end
|
上例也可以写成
1 2 3
| (0..5).each do |i| puts "Value of local variable is #{i}" end
|
break,终止最内部的循环。如果在块内调用,则终止相关块的方法(方法返回 nil)。
1 2 3 4 5 6
| for i in 0..5 if i > 2 then break end puts "Value of local variable is #{i}" end
|
next,跳到最内部循环的下一个迭代。如果在块内调用,则终止块的执行(yield 或调用返回 nil)。
1 2 3 4 5 6
| for i in 0..5 if i < 2 then next end puts "Value of local variable is #{i}" end
|
redo,重新开始最内部循环的该次迭代,不检查循环条件。如果在块内调用,则重新开始 yield 或 call。
1 2 3 4 5 6 7
| for i in 0..5 if i < 2 then puts "Value of local variable is #{i}" redo end end #这将产生以下结果,并会进入一个无限循环
|
retry,如果 retry 出现在 begin 表达式的 rescue 子句中,则从 begin 主体的开头重新开始。
1 2 3 4 5 6
| begin do_something # 抛出的异常 rescue # 处理错误 retry # 重新从 begin 开始 end
|
如果 retry 出现在迭代内、块内或者 for 表达式的主体内,则重新开始迭代调用。迭代的参数会重新评估。
1 2 3 4 5
| for i in 1..5 retry if i > 2 puts "Value of local variable is #{i}" end #这将产生以下结果,并会进入一个无限循环
|
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def test #不带参数的方法 puts "test" end test #output : test def test1(var1, var2) puts var1,var2 end test1(1,2) #or test1 1,2 空格可以去掉 def test(a1="Ruby", a2="Perl") #默认值 puts "The programming language is #{a1}" puts "The programming language is #{a2}" end test "C", "C++" test
|
返回值
1 2 3 4 5
| def test i = 100 j = 10 k = 0 end #返回最后一个声明的变量 k
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| return OR return 12 OR return 1,2,3 OR return x,y #自带tuple like python
|
可变数量的参数 like python
1 2 3 4 5 6 7 8 9 10 11 12
| def sample (*test) puts "The number of parameters is #{test.length}" for i in 0...test.length puts "The parameters are #{test[i]}" end end sample "Zara", "6", "F" sample "Mac", "36", "M", "MCA" list = ["Zara", "6", "F"] #也可以使用 array 加* 前缀 sample(*list)
|
类方法
1 2 3 4 5 6
| class Accounts def reading_charge end def Accounts.return_date #Accounts 可以用self 替换 end end
|
定义方法
块
- 块由大量的代码组成。
- 您需要给块取个名称。
- 块中的代码总是包含在大括号 {} 内。
- 块总是从与其具有相同名称的函数调用。这意味着如果您的块名称为 test,那么您要使用函数 test 来调用这个块。
您可以使用 yield 语句来调用块。
1 2 3 4 5 6
| def test yield 5 puts "You are in the method test" yield 100 end test {|i| puts "You are in the block #{i}"}
|
如果您想要传递多个参数,那么 yield 语句如下所示:
1 2
| yield a, b test {|a, b| statement}
|
复杂用法
1 2 3 4 5
| def test(var = 2) puts var yield(var) end test("bumaociyuan"){|name| puts "Hello world #{name}"}
|
但是如果方法的最后一个参数前带有 &,那么您可以向该方法传递一个块,且这个块可被赋给最后一个参数。如果 * 和 & 同时出现在参数列表中,& 应放在后面。
1 2 3 4
| def test(&block) block.call end test { puts "Hello World!"}
|
Module
模块常量命名与类常量命名类似,以大写字母开头。方法定义看起来也相似:模块方法定义与类方法定义类似。
通过类方法,您可以在类方法名称前面放置模块名称和一个点号来调用模块方法,您可以使用模块名称和两个冒号来引用一个常量
1 2 3 4 5 6 7 8 9 10 11
| \# 定义在 trig.rb 文件中的模块 module Trig PI = 3.141592654 def Trig.sin(x) # .. end def Trig.cos(x) # .. end end
|
require 语句
require 语句类似于 C 和 C++ 中的 include 语句以及 Java 中的 import 语句。如果一个第三方的程序想要使用任何已定义的模块,则可以简单地使用 Ruby require 语句来加载模块文件:
1 2 3 4 5 6 7
| $LOAD_PATH << '.' require 'trig.rb' require 'moral' y = Trig.sin(Trig::PI/4) wrongdoing = Moral.sin(Moral::VERY_BAD)
|
在这里,我们使用 $LOAD_PATH << ‘.’ 让 Ruby 知道必须在当前目录中搜索被引用的文件。如果您不想使用 $LOAD_PATH,那么您可以使用 require_relative 来从一个相对目录引用文件。
注意:在这里,文件包含相同的函数名称。所以,这会在引用调用程序时导致代码模糊,但是模块避免了这种代码模糊,而且我们可以使用模块的名称调用适当的函数。
support.rb
1 2 3 4 5 6 7 8 9
| module Week FIRST_DAY = "Sunday" def Week.weeks_in_month puts "You have four weeks in a month" end def Week.weeks_in_year puts "You have 52 weeks in a year" end end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| $LOAD_PATH << '.' require "support" class Decade include Week no_of_yrs=10 def no_of_months puts Week::FIRST_DAY number=10*12 puts number end end d1=Decade.new puts Week::FIRST_DAY Week.weeks_in_month Week.weeks_in_year d1.no_of_months
|
Mixins 多重继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| module A def a1 puts "a1" end def a2 puts "a2" end end module B def b1 puts "b1" end def b2 puts "b2" end end class Sample include A include B def s1 puts "s1" end end samp=Sample.new samp.a1 samp.a2 samp.b1 samp.b2 samp.s1 \#output a1 a2 b1 b2 s1
|
String
link
1 2 3 4 5 6 7 8 9
| x, y, z = 12, 36, 72 puts "The value of x is #{ x }." puts "The sum of x and y is #{ x + y }." puts "The average was #{ (x + y + z)/3 }." %{Ruby is fun.} 相当于 "Ruby is fun." %Q{ Ruby is fun. } 相当于 " Ruby is fun. " %q[Ruby is fun.] 相当于以单引号字符串 %x!ls! 相当于反勾号命令输出 `ls`
|
Array
link
数组的索引从 0 开始,这与 C 或 Java 中一样。一个负数的索引时相对于数组的末尾计数的,也就是说,索引为 -1 表示数组的最后一个元素,-2 表示数组中的倒数第二个元素,依此类推。
Ruby 数组可存储诸如 String、 Integer、 Fixnum、 Hash、 Symbol 等对象,甚至可以是其他 Array 对象。Ruby 数组不像其他语言中的数组那么刚性。当向数组添加元素时,Ruby 数组会自动增长。
创建数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| names = Array.new names = Array.new(20) names = Array.new(20) puts names.size # 返回 20 puts names.length # 返回 20 names = Array.new(4, "mac") puts "#{names}" #output macmacmacmac nums = Array.new(10) { |e| e = e * 2 } puts "#{nums}" #output 024681012141618 nums = Array.[](1, 2, 3, 4,5) nums = Array[1, 2, 3, 4,5] digits = Array(0..9) puts "#{digits}" #output 0123456789
|
哈希(Hash)
link
哈希(Hash)是类似 “employee” => “salary” 这样的键值对的集合。哈希的索引是通过任何对象类型的任意键来完成的,而不是一个整数索引,其他与数组相似。
通过键或值遍历哈希的顺序看起来是随意的,且通常不是按照插入顺序。如果您尝试通过一个不存在的键访问哈希,则方法会返回 nil。
日期 & 时间(Date & Time)
创建当前的日期和时间
1 2 3 4 5 6 7
| time1 = Time.new puts "Current Time : " + time1.inspect \# Time.now 是一个同义词 time2 = Time.now puts "Current Time : " + time2.inspect
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| time = Time.new \# Time 的组件 puts "Current Time : " + time.inspect puts time.year # => 日期的年份 puts time.month # => 日期的月份(1 到 12) puts time.day # => 一个月中的第几天(1 到 31) puts time.wday # => 一周中的星期几(0 是星期日) puts time.yday # => 365:一年中的第几天 puts time.hour # => 23:24 小时制 puts time.min # => 59 puts time.sec # => 59 puts time.usec # => 999999:微秒 puts time.zone # => "UTC":时区名称
|
范围(Range)
范围(Range)无处不在:January 到 December、 0 到 9、等等。Ruby 支持范围,并允许我们以不同的方式使用范围:
1 2 3
| (1..5) #==> 1, 2, 3, 4, 5 (1...5) #==> 1, 2, 3, 4 ('a'..'d') #==> 'a', 'b', 'c', 'd'
|
序列 1..100 是一个 Range 对象,包含了两个 Fixnum 对象的引用。如果需要,您可以使用 to_a 方法把范围转换为列表。尝试下面的实例:
1 2 3 4 5 6
| $, =", " # Array 值分隔符 range1 = (1..10).to_a range2 = ('bar'..'bat').to_a puts "#{range1}" puts "#{range2}"
|
each 迭代器
1 2 3
| collection.each do |variable| code end
|
1 2 3
| a = [1,2,3,4,5] b = a.collect{|x| 10*x} puts b
|
collect 方法不是数组间进行复制的正确方式。这里有另一个称为 clone 的方法,用于复制一个数组到另一个数组
文件的输入与输出
link
Ruby 提供了一整套 I/O 相关的方法,在内核(Kernel)模块中实现。所有的 I/O 方法派生自 IO 类。
类 IO 提供了所有基础的方法,比如 read、 write、 gets、 puts、 readline、 getc 和 printf。
本章节将讲解所有 Ruby 中可用的基础的 I/O 函数。如需了解更多的函数,请查看 Ruby 的 IO 类。
puts 语句
1 2 3 4
| val1 = "This is variable one" val2 = "This is variable two" puts val1 puts val2
|
gets 语句
1 2 3
| puts "Enter a value :" val = gets puts val
|
putc 语句
1 2
| str="Hello Ruby!" putc str
|
print 语句
1 2
| print "Hello World" print "Good Morning" #output Hello WorldGood Morning
|
打开和关闭文件
File.new 方法
您可以使用 File.new 方法创建一个 File 对象用于读取、写入或者读写,读写权限取决于 mode 字符串。最后,您可以使用 File.close 方法来关闭该文件。
1 2 3 4
| aFile = File.new("filename", "mode") # ... 处理文件 #filename 默认路径是当前路径,必须带extension 如 "support.rb" aFile.close
|
mode:
模式 |
描述 |
r |
只读模式。文件指针被放置在文件的开头。这是默认模式。 |
r+ |
读写模式。文件指针被放置在文件的开头。 |
w |
只写模式。如果文件存在,则重写文件。如果文件不存在,则创建一个新文件用于写入。 |
w+ |
读写模式。如果文件存在,则重写已存在的文件。如果文件不存在,则创建一个新文件用于读写。 |
a |
只写模式。如果文件存在,则文件指针被放置在文件的末尾。也就是说,文件是追加模式。如果文件不存在,则创建一个新文件用于写入。 |
a+ |
读写模式。如果文件存在,则文件指针被放置在文件的末尾。也就是说,文件是追加模式。如果文件不存在,则创建一个新文件用于读写。 |
读取和写入文件
sysread 方法
1 2 3 4 5 6 7
| aFile = File.new("input.txt", "r") if aFile content = aFile.sysread(20) puts content else puts "Unable to open file!" end
|
该语句将输入文件的头 20 个字符。文件指针将被放置在文件中第 21 个字符的位置。
syswrite 方法
1 2 3 4 5 6
| aFile = File.new("input.txt", "r+") if aFile aFile.syswrite("ABCDEF") else puts "Unable to open file!" end
|
该语句将写入 “ABCDEF” 到文件中。
each_byte 方法
1 2 3 4 5 6 7
| aFile = File.new("input.txt", "r+") if aFile aFile.syswrite("ABCDEF") aFile.each_byte {|ch| putc ch; putc ?. } else puts "Unable to open file!" end
|
IO.readlines 方法
类 File 是类 IO 的一个子类。类 IO 也有一些用于操作文件的方法。
IO.readlines 是 IO 类中的一个方法。该方法逐行返回文件的内容。下面的代码显示了方法 IO.readlines 的使用:
1 2 3
| arr = IO.readlines("input.txt") puts arr[0] puts arr[1]
|
IO.foreach 方法
1
| IO.foreach("input.txt"){|block| puts block}
|
重命名和删除文件
1 2 3 4 5
| \# 重命名文件 test1.txt 为 test2.txt File.rename( "test1.txt", "test2.txt" ) \# 删除文件 test2.txt File.delete("text2.txt")
|
文件模式与所有权
1 2
| file = File.new( "test.txt", "w" ) file.chmod( 0755 )
|
掩码 |
描述 |
0700 |
rwx 掩码,针对所有者 |
0400 |
r ,针对所有者 |
0200 |
w ,针对所有者 |
0100 |
x ,针对所有者 |
0070 |
rwx 掩码,针对所属组 |
0040 |
r ,针对所属组 |
0020 |
w ,针对所属组 |
0010 |
x ,针对所属组 |
0007 |
rwx 掩码,针对其他人 |
0004 |
r ,针对其他人 |
0002 |
w ,针对其他人 |
0001 |
x ,针对其他人 |
4000 |
执行时设置用户 ID |
2000 |
执行时设置所属组 ID |
1000 |
保存交换文本,甚至在使用后也会保存 |
文件查询
1 2
| #下面的命令在打开文件前检查文件是否已存在: File.open("file.rb") if File::exists?( "file.rb" )
|
您可以通过 Dir.pwd 查看当前目录:
1
| puts Dir.pwd # 返回当前目录,类似 /usr/bin
|
您可以使用 Dir.entries 获取指定目录内的文件和目录列表:
1
| puts Dir.entries("/usr/bin").join(' ')
|
Dir.entries 返回一个数组,包含指定目录内的所有项。Dir.foreach 提供了相同的功能:
1 2 3
| Dir.foreach("/usr/bin") do |entry| puts entry end
|
创建目录
1 2
| Dir.mkdir("mynewdir") Dir.mkdir( "mynewdir", 755 ) #掩码 755 设置所有者(owner)、所属组(group)、每个人(world [anyone])的权限为 rwxr-xr-x,其中 r = read 读取,w = write 写入,x = execute 执行。
|
删除目录
File 类和方法
link
Dir 类和方法
link
异常
link
面向对象
Ruby 是纯面向对象的语言,Ruby 中的一切都是以对象的形式出现。Ruby 中的每个值都是一个对象,即使是最原始的东西:字符串、数字,甚至连 true 和 false 都是对象。类本身也是一个对象,是 Class 类的一个实例。本章将向您讲解所有与 Ruby 面向对象相关的主要功能。
类用于指定对象的形式,它结合了数据表示法和方法,把数据整理成一个整齐的包。类中的数据和方法被称为类的成员。
类定义
按照惯例,名称必须以大写字母开头,如果包含多个单词,每个单词首字母大写,但此间没有分隔符(例如:CamelCase)。
1 2 3 4 5 6
| class Box code end box1 = Box.new box2 = Box.new
|
initialize 方法
1 2 3 4 5
| class Box def initialize(w,h) @width, @height = w, h end end
|
实例变量
1 2 3 4 5 6
| class Box def initialize(w,h) # 给实例变量赋值 @width, @height = w, h end end
|
访问器 & 设置器 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| # 定义类 class Box # 构造器方法 def initialize(w,h) @width, @height = w, h end # 访问器方法 def printWidth @width end def printHeight @height end end # 创建对象 box = Box.new(10, 20) # 使用访问器方法 x = box.printWidth() y = box.printHeight() puts "Width of the box is : #{x}" puts "Height of the box is : #{y}"
|
类方法 & 类变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Box # 初始化类变量 @@count = 0 def initialize(w,h) # 给实例变量赋值 @width, @height = w, h @@count += 1 end def self.printCount() #self 可以用Box 替换 puts "Box count is : #@@count" end end # 创建两个对象 box1 = Box.new(10, 20) box2 = Box.new(30, 100) # 调用类方法来输出盒子计数 Box.printCount()
|
访问控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| # 定义类 class Box # 构造器方法 def initialize(w,h) @width, @height = w, h end # 实例方法默认是 public 的 def getArea getWidth() * getHeight end # 定义 private 的访问器方法 def getWidth @width end def getHeight @height end # make them private private :getWidth, :getHeight # 用于输出面积的实例方法 def printArea @area = getWidth() * getHeight puts "Big box area is : #@area" end # 让实例方法是 protected 的 protected :printArea end # 创建对象 box = Box.new(10, 20) # 调用实例方法 a = box.getArea() puts "Area of the box is : #{a}" # 尝试调用 protected 的实例方法 box.printArea()
|
运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Box def initialize(w,h) # 初始化 width 和 height @width,@height = w, h end def +(other) # 定义 + 来执行向量加法 Box.new(@width + other.width, @height + other.height) end def -@ # 定义一元运算符 - 来对 width 和 height 求反 Box.new(-@width, -@height) end def *(scalar) # 执行标量乘法 Box.new(@width*scalar, @height*scalar) end def width @width end def height @height end end box1 = Box.new(10,20); puts (box1 * 3).height
|
冻结对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| # 定义类 class Box # 构造器方法 def initialize(w,h) @width, @height = w, h end # 访问器方法 def getWidth @width end def getHeight @height end # 设置器方法 def setWidth=(value) @width = value end def setHeight=(value) @height = value end end # 创建对象 box = Box.new(10, 20) # 让我们冻结该对象 box.freeze if( box.frozen? ) puts "Box object is frozen object" else puts "Box object is normal object" end # 现在尝试使用设置器方法 box.setWidth = 30 box.setHeight = 50 # 使用访问器方法 x = box.getWidth() y = box.getHeight() puts "Width of the box is : #{x}" puts "Height of the box is : #{y}"
|
类常量
您可以在类的内部定义一个常量,通过把一个直接的数值或字符串值赋给一个变量来定义的,常量的定义不需要使用 @ 或 @@。按照惯例,常量的名称使用大写
。
一旦常量被定义,您就不能改变它的值
,您可以在类的内部直接访问常量,就像是访问变量一样,但是如果您想要在类的外部访问常量,那么您必须使用 classname::constant,如下面实例所示。
1 2 3 4 5
| class Box NAME = "box name" end puts Box::NAME
|
使用 allocate 创建对象
可能有一种情况,您想要在不调用对象构造器 initialize 的情况下创建对象,即,使用 new 方法创建对象,在这种情况下,您可以调用 allocate 来创建一个未初始化的对象,如下面实例所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Box attr_accessor :width , :height def initialize(w,h) @width, @height = w,h end def getArea @width * @height end end box1 = Box.new(10,20) puts box1.getArea() box2 = Box.allocate #报错,好像没什么用 box2.getArea()
|
正则表达式
语法
正则表达式从字面上看是一种介于斜杠之间或介于跟在 %r 后的任意分隔符之间的模式,如下所示:
1 2 3
| /pattern/ /pattern/im # 可以指定选项 %r!/usr/local! # 一般的分隔的正则表达式
|