Ruby 快速指南



Ruby - 概述

Ruby 是一種純面向物件的程式語言。它由日本程式設計師松本行弘於 1993 年建立。

您可以在 Ruby 郵件列表 www.ruby-lang.org 上找到松本行弘的名字。在 Ruby 社群中,松本行弘也被稱為 Matz。

Ruby 是“程式設計師的最佳朋友”。

Ruby 的功能類似於 Smalltalk、Perl 和 Python。Perl、Python 和 Smalltalk 都是指令碼語言。Smalltalk 是一種真正的面嚮物件語言。Ruby 與 Smalltalk 一樣,是一種完美的面嚮物件語言。使用 Ruby 語法比使用 Smalltalk 語法容易得多。

Ruby 的特性

  • Ruby 是開源的,並且可以在 Web 上免費獲得,但它受許可證約束。

  • Ruby 是一種通用的解釋型程式語言。

  • Ruby 是一種真正面向物件的程式語言。

  • Ruby 是一種類似於 Python 和 PERL 的伺服器端指令碼語言。

  • Ruby 可用於編寫通用閘道器介面 (CGI) 指令碼。

  • Ruby 可以嵌入到超文字標記語言 (HTML) 中。

  • Ruby 具有簡潔易懂的語法,使新開發者能夠非常快速和輕鬆地學習。

  • Ruby 的語法類似於許多程式語言,如 C++ 和 Perl。

  • Ruby 具有很強的可擴充套件性,用 Ruby 編寫的龐大程式易於維護。

  • Ruby 可用於開發 Internet 和 Intranet 應用程式。

  • Ruby 可以安裝在 Windows 和 POSIX 環境中。

  • Ruby 支援許多 GUI 工具,如 Tcl/Tk、GTK 和 OpenGL。

  • Ruby 可以輕鬆連線到 DB2、MySQL、Oracle 和 Sybase。

  • Ruby 有一套豐富的內建函式,可以直接在 Ruby 指令碼中使用。

您需要的工具

要執行本教程中討論的示例,您需要一臺最新的計算機,例如英特爾酷睿 i3 或 i5,至少 2GB RAM(建議 4GB RAM)。您還需要以下軟體:

  • Linux 或 Windows 95/98/2000/NT 或 Windows 7 作業系統。

  • Apache 1.3.19-5 Web 伺服器。

  • Internet Explorer 5.0 或更高版本的 Web 瀏覽器。

  • Ruby 1.8.5

本教程將提供建立使用 Ruby 的 GUI、網路和 Web 應用程式所需的必要技能。它還將討論擴充套件和嵌入 Ruby 應用程式。

接下來是什麼?

下一章將指導您如何獲取 Ruby 及其文件。最後,它將指導您如何安裝 Ruby 並準備一個開發 Ruby 應用程式的環境。

Ruby - 環境設定

本地環境設定

如果您仍然希望為 Ruby 程式語言設定您的環境,那麼讓我們繼續。本教程將教您所有與環境設定相關的重點主題。我們建議您首先瀏覽以下主題,然後再繼續:

流行的 Ruby 編輯器

要編寫 Ruby 程式,您需要一個編輯器:

  • 如果您在 Windows 機器上工作,則可以使用任何簡單的文字編輯器,如記事本或 Edit plus。

  • VIM (Vi IMproved) 是一款非常簡單的文字編輯器。它幾乎存在於所有 Unix 機器上,現在也適用於 Windows。否則,您可以使用您喜歡的 vi 編輯器來編寫 Ruby 程式。

  • RubyWin 是 Windows 的 Ruby 整合開發環境 (IDE)。

  • Ruby 開發環境 (RDE) 也是 Windows 使用者的非常好的 IDE。

互動式 Ruby (IRb)

互動式 Ruby (IRb) 提供了一個用於實驗的 Shell。在 IRb Shell 中,您可以立即逐行查看錶達式的結果。

此工具隨 Ruby 安裝一起提供,因此您無需執行任何額外操作即可使用 IRb。

只需在命令提示符下鍵入irb,即可啟動互動式 Ruby 會話,如下所示:

$irb
irb 0.6.1(99/09/16)
irb(main):001:0> def hello
irb(main):002:1> out = "Hello World"
irb(main):003:1> puts out
irb(main):004:1> end
nil
irb(main):005:0> hello
Hello World
nil
irb(main):006:0>

不要擔心我們在這裡做了什麼。您將在後續章節中學習所有這些步驟。

接下來是什麼?

我們現在假設您有一個可用的 Ruby 環境,並且您已準備好編寫第一個 Ruby 程式。下一章將教您如何編寫 Ruby 程式。

Ruby - 語法

讓我們在 Ruby 中編寫一個簡單的程式。所有 Ruby 檔案都將具有副檔名.rb。因此,將以下原始碼放入 test.rb 檔案中。

即時演示
#!/usr/bin/ruby -w

puts "Hello, Ruby!";

這裡,我們假設您在 /usr/bin 目錄中提供了 Ruby 直譯器。現在,嘗試按如下方式執行此程式:

$ ruby test.rb

這將產生以下結果:

Hello, Ruby!

您已經看到了一個簡單的 Ruby 程式,現在讓我們瞭解一些與 Ruby 語法相關的基本概念。

Ruby 程式中的空白字元

空格和製表符等空白字元通常在 Ruby 程式碼中被忽略,除非它們出現在字串中。但是,有時它們用於解釋模稜兩可的語句。當啟用 -w 選項時,此類解釋會產生警告。

示例

a + b is interpreted as a+b ( Here a is a local variable)
a  +b is interpreted as a(+b) ( Here a is a method call)

Ruby 程式中的行尾

Ruby 將分號和換行符解釋為語句的結束。但是,如果 Ruby 在行尾遇到運算子(如 +、- 或反斜槓),則表示語句的繼續。

Ruby 識別符號

識別符號是變數、常量和方法的名稱。Ruby 識別符號區分大小寫。這意味著 Ram 和 RAM 在 Ruby 中是兩個不同的識別符號。

Ruby 識別符號名稱可以由字母數字字元和下劃線字元(_)組成。

保留字

以下列表顯示了 Ruby 中的保留字。這些保留字不能用作常量或變數名。但是,它們可以用作方法名。

BEGIN do next then
END else nil true
alias elsif not undef
and end or unless
begin ensure redo until
break false rescue when
case for retry while
class if return while
def in self __FILE__
defined? module super __LINE__

Ruby 中的文件

“文件”指的是從多行構建字串。在 << 後,您可以指定一個字串或一個識別符號來終止字串文字,並且從當前行到終止符的所有行都是字串的值。

如果終止符被引用,則引號的型別確定面向行的字串文字的型別。請注意,<< 和終止符之間不能有空格。

以下是一些不同的示例:

即時演示
#!/usr/bin/ruby -w

print <<EOF
   This is the first way of creating
   here document ie. multiple line string.
EOF

print <<"EOF";                # same as above
   This is the second way of creating
   here document ie. multiple line string.
EOF

print <<`EOC`                 # execute commands
	echo hi there
	echo lo there
EOC

print <<"foo", <<"bar"  # you can stack them
	I said foo.
foo
	I said bar.
bar

這將產生以下結果:

   This is the first way of creating
   her document ie. multiple line string.
   This is the second way of creating
   her document ie. multiple line string.
hi there
lo there
      I said foo.
      I said bar.

Ruby BEGIN 語句

語法

BEGIN {
   code
}

宣告在程式執行之前呼叫的程式碼

示例

即時演示
#!/usr/bin/ruby

puts "This is main Ruby Program"

BEGIN {
   puts "Initializing Ruby Program"
}

這將產生以下結果:

Initializing Ruby Program
This is main Ruby Program

Ruby END 語句

語法

END {
   code
}

宣告在程式結束時呼叫的程式碼

示例

即時演示
#!/usr/bin/ruby

puts "This is main Ruby Program"

END {
   puts "Terminating Ruby Program"
}
BEGIN {
   puts "Initializing Ruby Program"
}

這將產生以下結果:

Initializing Ruby Program
This is main Ruby Program
Terminating Ruby Program

Ruby 註釋

註釋隱藏了 Ruby 直譯器的一行、一行的一部分或幾行。您可以在行的開頭使用井號 (#):

# I am a comment. Just ignore me.

或者,註釋可以位於語句或表示式之後的同一行:

name = "Madisetti" # This is again comment

您可以按如下方式註釋多行:

# This is a comment.
# This is a comment, too.
# This is a comment, too.
# I said that already.

這是另一種形式。此塊註釋使用 =begin/=end 隱藏了幾個直譯器行:

=begin
This is a comment.
This is a comment, too.
This is a comment, too.
I said that already.
=end

Ruby - 類和物件

Ruby 是一種完美的面向物件程式語言。面向物件程式語言的特性包括:

  • 資料封裝
  • 資料抽象
  • 多型性
  • 繼承

這些特性已在 面向物件 Ruby 一章中討論。

面向物件程式涉及類和物件。類是建立單個物件的藍圖。用面向物件的術語來說,我們說您的腳踏車是稱為腳踏車的物件類的一個例項。

以任何車輛為例,它包含車輪、馬力和燃油或油箱容量。這些特徵構成了類 Vehicle 的資料成員。您可以藉助這些特徵來區分不同的車輛。

車輛還可以具有一些功能,例如停止、駕駛和加速。即使這些功能也構成了類 Vehicle 的資料成員。因此,您可以將類定義為特徵和功能的組合。

類 Vehicle 可以定義為 -

Class Vehicle {

   Number no_of_wheels
   Number horsepower
   Characters type_of_tank
   Number Capacity
   Function speeding {
   }
   
   Function driving {
   }
   
   Function halting {
   }
}

透過為這些資料成員分配不同的值,您可以形成類 Vehicle 的多個例項。例如,飛機有三個輪子,馬力為 1000,燃料為油箱型別,容量為 100 升。同樣,汽車有四個輪子,馬力為 200,汽油為油箱型別,容量為 25 升。

在 Ruby 中定義類

要使用 Ruby 實現面向物件程式設計,您首先需要學習如何在 Ruby 中建立物件和類。

Ruby 中的類總是以關鍵字class開頭,後跟類名。名稱始終應以大寫字母開頭。類Customer可以顯示為 -

class Customer
end

您使用關鍵字end終止類。class中的所有資料成員都位於類定義和end關鍵字之間。

Ruby 類中的變數

Ruby 提供四種類型的變數 -

  • 區域性變數 - 區域性變數是在方法中定義的變數。區域性變數在方法外部不可用。您將在後續章節中看到有關方法的更多詳細資訊。區域性變數以小寫字母或 _ 開頭。

  • 例項變數 - 例項變數在任何特定例項或物件的各種方法中都可用。這意味著例項變數因物件而異。例項變數前面是 at 符號 (@),後跟變數名。

  • 類變數 - 類變數在不同的物件之間可用。類變數屬於類,是類的特徵。它們前面是符號 @@,後跟變數名。

  • 全域性變數 - 類變數在類之間不可用。如果要有一個在類之間可用的單個變數,則需要定義一個全域性變數。全域性變數始終以美元符號 ($) 開頭。

示例

使用類變數 @@no_of_customers,您可以確定正在建立的物件的數量。這使得能夠推匯出客戶的數量。

class Customer
   @@no_of_customers = 0
end

使用 new 方法在 Ruby 中建立物件

物件是類的例項。您現在將學習如何在 Ruby 中建立類的物件。您可以使用類的new方法在 Ruby 中建立物件。

new方法是一種獨特的型別方法,它是在 Ruby 庫中預定義的。new 方法屬於class方法。

以下是如何建立類 Customer 的兩個物件 cust1 和 cust2 的示例 -

cust1 = Customer. new
cust2 = Customer. new

這裡,cust1 和 cust2 是兩個物件的名。您在物件名稱後寫上等號 (=),然後是類名。然後,點運算子和關鍵字new將緊隨其後。

建立 Ruby 物件的自定義方法

您可以將引數傳遞給new方法,這些引數可用於初始化類變數。

當您計劃宣告帶有引數的new方法時,需要在類建立時宣告initialize方法。

initialize方法是一種特殊型別的方法,當使用引數呼叫類的new方法時,它將被執行。

以下是如何建立 initialize 方法的示例 -

class Customer
   @@no_of_customers = 0
   def initialize(id, name, addr)
      @cust_id = id
      @cust_name = name
      @cust_addr = addr
   end
end

在此示例中,您聲明瞭initialize方法,其中id、nameaddr作為區域性變數。這裡,defend用於定義 Ruby 方法initialize。您將在後續章節中學習更多有關方法的資訊。

initialize方法中,您將這些區域性變數的值傳遞給例項變數 @cust_id、@cust_name 和 @cust_addr。這裡區域性變數儲存與 new 方法一起傳遞的值。

現在,您可以按如下方式建立物件 -

cust1 = Customer.new("1", "John", "Wisdom Apartments, Ludhiya")
cust2 = Customer.new("2", "Poul", "New Empire road, Khandala")

Ruby 類中的成員函式

在 Ruby 中,函式稱為方法。class中的每個方法都以關鍵字def開頭,後跟方法名。

方法名始終以小寫字母為佳。您使用關鍵字end結束 Ruby 中的方法。

以下是如何定義 Ruby 方法的示例 -

class Sample
   def function
      statement 1
      statement 2
   end
end

這裡,statement 1statement 2是類 Sample 內function方法主體的一部分。這些語句可以是任何有效的 Ruby 語句。例如,我們可以使用方法puts列印Hello Ruby,如下所示 -

class Sample
   def hello
      puts "Hello Ruby!"
   end
end

現在在以下示例中,建立一個 Sample 類的物件並呼叫hello方法,檢視結果 -

即時演示
#!/usr/bin/ruby

class Sample
   def hello
      puts "Hello Ruby!"
   end
end

# Now using above class to create objects
object = Sample. new
object.hello

這將產生以下結果:

Hello Ruby!

簡單案例研究

如果您想對類和物件進行更多練習,以下是一個案例研究。

Ruby 類案例研究

Ruby - 變數、常量和字面量

變數是記憶體位置,用於儲存任何程式要使用的資料。

Ruby 支援五種型別的變數。您已經在上一章中瞭解了這些變數的簡要說明。本章將詳細解釋這五種型別的變數。

Ruby 全域性變數

全域性變數以 $ 開頭。未初始化的全域性變數的值為 nil,並且在使用 -w 選項時會產生警告。

對全域性變數的賦值會更改全域性狀態。不建議使用全域性變數。它們使程式變得難以理解。

以下是一個顯示全域性變數用法的示例。

即時演示
#!/usr/bin/ruby

$global_variable = 10
class Class1
   def print_global
      puts "Global variable in Class1 is #$global_variable"
   end
end
class Class2
   def print_global
      puts "Global variable in Class2 is #$global_variable"
   end
end

class1obj = Class1.new
class1obj.print_global
class2obj = Class2.new
class2obj.print_global

這裡 $global_variable 是一個全域性變數。這將產生以下結果 -

注意 - 在 Ruby 中,您可以透過在變數或常量之前放置一個雜湊 (#) 字元來訪問任何變數或常量的值。

Global variable in Class1 is 10
Global variable in Class2 is 10

Ruby 例項變數

例項變數以 @ 開頭。未初始化的例項變數的值為nil,並且在使用 -w 選項時會產生警告。

以下是一個顯示例項變數用法的示例。

即時演示
#!/usr/bin/ruby

class Customer
   def initialize(id, name, addr)
      @cust_id = id
      @cust_name = name
      @cust_addr = addr
   end
   def display_details()
      puts "Customer id #@cust_id"
      puts "Customer name #@cust_name"
      puts "Customer address #@cust_addr"
   end
end

# Create Objects
cust1 = Customer.new("1", "John", "Wisdom Apartments, Ludhiya")
cust2 = Customer.new("2", "Poul", "New Empire road, Khandala")

# Call Methods
cust1.display_details()
cust2.display_details()

這裡,@cust_id、@cust_name 和 @cust_addr 是例項變數。這將產生以下結果 -

Customer id 1
Customer name John
Customer address Wisdom Apartments, Ludhiya
Customer id 2
Customer name Poul
Customer address New Empire road, Khandala

Ruby 類變數

類變數以 @@ 開頭,並且必須在可以在方法定義中使用之前進行初始化。

引用未初始化的類變數會產生錯誤。類變數在定義類變數的類或模組的後代之間共享。

覆蓋類變數會產生帶有 -w 選項的警告。

以下是一個顯示類變數用法的示例 -

即時演示
#!/usr/bin/ruby

class Customer
   @@no_of_customers = 0
   def initialize(id, name, addr)
      @cust_id = id
      @cust_name = name
      @cust_addr = addr
   end
   def display_details()
      puts "Customer id #@cust_id"
      puts "Customer name #@cust_name"
      puts "Customer address #@cust_addr"
   end
   def total_no_of_customers()
      @@no_of_customers += 1
      puts "Total number of customers: #@@no_of_customers"
   end
end

# Create Objects
cust1 = Customer.new("1", "John", "Wisdom Apartments, Ludhiya")
cust2 = Customer.new("2", "Poul", "New Empire road, Khandala")

# Call Methods
cust1.total_no_of_customers()
cust2.total_no_of_customers()

這裡 @@no_of_customers 是一個類變數。這將產生以下結果 -

Total number of customers: 1
Total number of customers: 2

Ruby 區域性變數

區域性變數以小寫字母或 _ 開頭。區域性變數的作用域從類、模組、def 或 do 到相應的 end,或從塊的起始花括號到結束花括號 {}。

當引用未初始化的區域性變數時,它會被解釋為對沒有引數的方法的呼叫。

對未初始化的區域性變數的賦值也充當變數宣告。變數從存在到當前作用域結束。區域性變數的生命週期由 Ruby 在解析程式時確定。

在上面的示例中,區域性變數是 id、name 和 addr。

Ruby 常量

常量以大寫字母開頭。在類或模組內定義的常量可以從該類或模組內部訪問,在類或模組外部定義的常量可以在全域性範圍內訪問。

常量不能在方法內定義。引用未初始化的常量會產生錯誤。對已初始化的常量進行賦值會產生警告。

即時演示
#!/usr/bin/ruby

class Example
   VAR1 = 100
   VAR2 = 200
   def show
      puts "Value of first Constant is #{VAR1}"
      puts "Value of second Constant is #{VAR2}"
   end
end

# Create Objects
object = Example.new()
object.show

這裡 VAR1 和 VAR2 是常量。這將產生以下結果 -

Value of first Constant is 100
Value of second Constant is 200

Ruby 偽變數

它們是具有區域性變數外觀但行為類似於常量的特殊變數。您不能為這些變數分配任何值。

  • self - 當前方法的接收者物件。

  • true - 表示真的值。

  • false - 表示假的的值。

  • nil - 表示未定義的值。

  • __FILE__ - 當前原始檔的名稱。

  • __LINE__ - 原始檔中的當前行號。

Ruby 基本字面量

Ruby 用於字面量的規則簡單直觀。本節解釋所有基本的 Ruby 字面量。

整數

Ruby 支援整數。整數的範圍可以從 -230 到 230-1 或 -262 到 262-1。在此範圍內的整數是類Fixnum的物件,在此範圍之外的整數儲存在類Bignum的物件中。

您可以使用可選的前導符號、可選的基數指示符(0 表示八進位制、0x 表示十六進位制或 0b 表示二進位制),後跟適當基數的數字字串來編寫整數。下劃線字元在數字字串中被忽略。

您還可以獲取與 ASCII 字元對應的整數值,或者透過在其前面加上問號來轉義該序列。

示例

123                  # Fixnum decimal
1_234                # Fixnum decimal with underline
-500                 # Negative Fixnum
0377                 # octal
0xff                 # hexadecimal
0b1011               # binary
?a                   # character code for 'a'
?\n                  # code for a newline (0x0a)
12345678901234567890 # Bignum

注意 - 類和物件在本教程的單獨章節中進行了解釋。

浮點數

Ruby 支援浮點數。它們也是數字,但帶有小數。浮點數是類Float的物件,可以是以下任何一種 -

示例

123.4                # floating point value
1.0e6                # scientific notation
4E20                 # dot not required
4e+20                # sign before exponential

字串字面量

Ruby 字串只是 8 位位元組的序列,它們是類 String 的物件。雙引號字串允許替換和反斜槓表示法,但單引號字串不允許替換,僅允許對 \\ 和 \' 使用反斜槓表示法。

示例

即時演示
#!/usr/bin/ruby -w

puts 'escape using "\\"';
puts 'That\'s right';

這將產生以下結果:

escape using "\"
That's right

您可以使用序列#{ expr }將任何 Ruby 表示式的值替換到字串中。這裡,expr 可以是任何 Ruby 表示式。

即時演示
#!/usr/bin/ruby -w

puts "Multiplication Value : #{24*60*60}";

這將產生以下結果:

Multiplication Value : 86400

反斜槓表示法

以下是 Ruby 支援的反斜槓表示法列表 -

符號表示 表示的字元
\n 換行符 (0x0a)
\r 回車符 (0x0d)
\f 換頁符 (0x0c)
\b 退格符 (0x08)
\a 響鈴 (0x07)
\e 轉義符 (0x1b)
\s 空格 (0x20)
\nnn 八進位制表示法 (n 為 0-7)
\xnn 十六進位制表示法 (n 為 0-9、a-f 或 A-F)
\cx, \C-x 控制-x
\M-x Meta-x (c | 0x80)
\M-\C-x Meta-Control-x
\x 字元 x

有關 Ruby 字串的更多詳細資訊,請參閱 Ruby 字串

Ruby 陣列

Ruby 陣列的字面量是透過將一系列以逗號分隔的物件引用放在方括號之間建立的。尾隨逗號將被忽略。

示例

即時演示
#!/usr/bin/ruby

ary = [  "fred", 10, 3.14, "This is a string", "last element", ]
ary.each do |i|
   puts i
end

這將產生以下結果:

fred
10
3.14
This is a string
last element

有關 Ruby 陣列的更多詳細資訊,請參閱 Ruby 陣列

Ruby 雜湊

Ruby 雜湊的字面量是透過將鍵/值對列表放在大括號之間建立的,鍵和值之間可以使用逗號或序列 =>。尾隨逗號將被忽略。

示例

即時演示
#!/usr/bin/ruby

hsh = colors = { "red" => 0xf00, "green" => 0x0f0, "blue" => 0x00f }
hsh.each do |key, value|
   print key, " is ", value, "\n"
end

這將產生以下結果:

red is 3840
green is 240
blue is 15

有關 Ruby 雜湊的更多詳細資訊,請參閱 Ruby 雜湊

Ruby 範圍

範圍表示一個區間,它是一組具有起始值和結束值的數值。可以使用 s..e 和 s...e 字面量或 Range.new 構造範圍。

使用 .. 構造的範圍從起始值到結束值(包括結束值)。使用 ... 建立的範圍不包括結束值。當用作迭代器時,範圍將返回序列中的每個值。

範圍 (1..5) 表示它包含 1、2、3、4、5 個值,範圍 (1...5) 表示它包含 1、2、3、4 個值。

示例

即時演示
#!/usr/bin/ruby

(10..15).each do |n| 
   print n, ' ' 
end

這將產生以下結果:

10 11 12 13 14 15

有關 Ruby 範圍的更多詳細資訊,請參閱 Ruby 範圍

Ruby - 運算子

Ruby 支援豐富的運算子集,正如您對現代語言的期望一樣。大多數運算子實際上是方法呼叫。例如,a + b 被解釋為 a.+(b),其中變數 a 所引用的物件中的 + 方法被呼叫,b 作為其引數。

對於每個運算子 (+ - * / % ** & | ^ << >> && ||),都有一種相應的簡寫賦值運算子形式(+= -= 等)。

Ruby 算術運算子

假設變數 a 為 10,變數 b 為 20,則 −

運算子 描述 示例
+ 加法 − 將運算子兩側的值相加。 a + b 將得到 30
減法 減法 − 從左運算元中減去右運算元。 a - b 將得到 -10
* 乘法 − 將運算子兩側的值相乘。 a * b 將得到 200
/ 除法 − 將左運算元除以右運算元。 b / a 將得到 2
% 取模 − 將左運算元除以右運算元並返回餘數。 b % a 將得到 0
** 指數 − 對運算子執行指數(冪)計算。 a**b 將得到 10 的 20 次冪

Ruby 比較運算子

假設變數 a 為 10,變數 b 為 20,則 −

運算子 描述 示例
== 檢查兩個運算元的值是否相等,如果相等,則條件為真。 (a == b) 不為真。
!= 檢查兩個運算元的值是否不相等,如果不相等,則條件為真。 (a != b) 為真。
> 檢查左運算元的值是否大於右運算元的值,如果大於,則條件為真。 (a > b) 不為真。
< 檢查左運算元的值是否小於右運算元的值,如果小於,則條件為真。 (a < b) 為真。
>= 檢查左運算元的值是否大於或等於右運算元的值,如果大於或等於,則條件為真。 (a >= b) 不為真。
<= 檢查左運算元的值是否小於或等於右運算元的值,如果小於或等於,則條件為真。 (a <= b) 為真。
<=> 組合比較運算子。如果第一個運算元等於第二個運算元,則返回 0;如果第一個運算元大於第二個運算元,則返回 1;如果第一個運算元小於第二個運算元,則返回 -1。 (a <=> b) 返回 -1。
=== 用於在 case 語句的 when 子句中測試相等性。 (1...10) === 5 返回 true。
.eql? 如果接收者和引數具有相同的型別和相等的值,則返回 true。 1 == 1.0 返回 true,但 1.eql?(1.0) 返回 false。
equal? 如果接收者和引數具有相同的物件 ID,則返回 true。 如果 aObj 是 bObj 的副本,則 aObj == bObj 為 true,a.equal?bObj 為 false,但 a.equal?aObj 為 true。

Ruby 賦值運算子

假設變數 a 為 10,變數 b 為 20,則 −

運算子 描述 示例
= 簡單賦值運算子,將值從右側運算元賦值給左側運算元。 c = a + b 將 a + b 的值賦給 c
+= 加法並賦值運算子,將右運算元加到左運算元上並將結果賦值給左運算元。 c += a 等價於 c = c + a
-= 減法並賦值運算子,從左運算元中減去右運算元並將結果賦值給左運算元。 c -= a 等價於 c = c - a
*= 乘法並賦值運算子,將右運算元乘以左運算元並將結果賦值給左運算元。 c *= a 等價於 c = c * a
/= 除法並賦值運算子,將左運算元除以右運算元並將結果賦值給左運算元。 c /= a 等價於 c = c / a
%= 取模並賦值運算子,使用兩個運算元進行取模並將結果賦值給左運算元。 c %= a 等價於 c = c % a
**= 指數並賦值運算子,對運算子執行指數(冪)計算並將值賦值給左運算元。 c **= a 等價於 c = c ** a

Ruby 並行賦值

Ruby 還支援變數的並行賦值。這使得可以使用一行 Ruby 程式碼初始化多個變數。例如 −

a = 10
b = 20
c = 30

可以使用並行賦值更快地宣告此內容 −

a, b, c = 10, 20, 30

並行賦值也可用於交換兩個變數中儲存的值 −

a, b = b, c

Ruby 位運算子

位運算子作用於位並執行逐位運算。

假設 a = 60;b = 13;現在,以二進位制格式,它們將如下所示 −

 a    =  0011 1100
 b    =  0000 1101
 ------------------
 a&b  =  0000 1100
 a|b  =  0011 1101
 a^b  =  0011 0001
 ~a   =  1100 0011

Ruby 語言支援以下位運算子。

運算子 描述 示例
& 二進位制 AND 運算子如果位同時存在於兩個運算元中,則將其複製到結果中。 (a & b) 將得到 12,即 0000 1100
| 二進位制 OR 運算子如果位存在於任何一個運算元中,則將其複製。 (a | b) 將得到 61,即 0011 1101
^ 二進位制 XOR 運算子如果位在一個運算元中設定,但在另一個運算元中未設定,則將其複製。 (a ^ b) 將得到 49,即 0011 0001
~ 二進位制一補碼運算子是單目運算子,其作用是“翻轉”位。 (~a ) 將得到 -61,由於帶符號二進位制數,因此在 2 的補碼形式中為 1100 0011。
<< 二進位制左移運算子。左運算元的值向左移動由右運算元指定的位數。 a << 2 將得到 240,即 1111 0000
>> 二進位制右移運算子。左運算元的值向右移動由右運算元指定的位數。 a >> 2 將得到 15,即 0000 1111

Ruby 邏輯運算子

Ruby 語言支援以下邏輯運算子

假設變數 a 為 10,變數 b 為 20,則 −

運算子 描述 示例
and 稱為邏輯 AND 運算子。如果兩個運算元都為真,則條件為真。 (a and b) 為真。
or 稱為邏輯 OR 運算子。如果兩個運算元中的任何一個非零,則條件為真。 (a or b) 為真。
&& 稱為邏輯 AND 運算子。如果兩個運算元都非零,則條件為真。 (a && b) 為真。
|| 稱為邏輯 OR 運算子。如果兩個運算元中的任何一個非零,則條件為真。 (a || b) 為真。
! 稱為邏輯 NOT 運算子。用於反轉其運算元的邏輯狀態。如果條件為真,則邏輯 NOT 運算子將使其變為假。 !(a && b) 為假。
not 稱為邏輯 NOT 運算子。用於反轉其運算元的邏輯狀態。如果條件為真,則邏輯 NOT 運算子將使其變為假。 not(a && b) 為假。

Ruby 三元運算子

還有一個稱為三元運算子的運算子。它首先評估表示式的真假值,然後根據評估結果執行兩個給定語句之一。條件運算子具有以下語法 −

運算子 描述 示例
? : 條件表示式 如果條件為真 ? 則為值 X : 否則為值 Y

Ruby 範圍運算子

Ruby 中的序列範圍用於建立一系列連續的值 - 由起始值、結束值和介於兩者之間的值範圍組成。

在 Ruby 中,這些序列是使用 ".." 和 "..." 範圍運算子建立的。兩點形式建立包含範圍,而三點形式建立不包括指定的高值的範圍。

運算子 描述 示例
.. 建立從起始點到結束點(包括結束點)的範圍。 1..10 建立從 1 到 10(包括 10)的範圍。
... 建立從起始點到結束點(不包括結束點)的範圍。 1...10 建立從 1 到 9 的範圍。

Ruby defined? 運算子

defined? 是一個特殊的運算子,它採用方法呼叫的形式來確定傳遞的表示式是否已定義。它返回表示式的描述字串,或者如果表示式未定義,則返回 nil

defined? 運算子有多種用法

用法 1

defined? variable # True if variable is initialized

例如

foo = 42
defined? foo    # => "local-variable"
defined? $_     # => "global-variable"
defined? bar    # => nil (undefined)

用法 2

defined? method_call # True if a method is defined

例如

defined? puts        # => "method"
defined? puts(bar)   # => nil (bar is not defined here)
defined? unpack      # => nil (not defined here)

用法 3

# True if a method exists that can be called with super user
defined? super

例如

defined? super     # => "super" (if it can be called)
defined? super     # => nil (if it cannot be)

用法 4

defined? yield   # True if a code block has been passed

例如

defined? yield    # => "yield" (if there is a block passed)
defined? yield    # => nil (if there is no block)

Ruby 點 "." 和雙冒號 "::" 運算子

透過在模組方法名稱前加上模組名稱和一個句點來呼叫模組方法,並使用模組名稱和兩個冒號來引用常量。

:: 是一個一元運算子,它允許:在類或模組中定義的常量、例項方法和類方法從類或模組外部的任何地方訪問。

請記住在 Ruby 中,類和方法也可以被視為常量。

您只需要在 :: Const_name 前加上返回相應類或模組物件的表示式即可。

如果未使用字首表示式,則預設使用主 Object 類。

以下提供兩個示例 −

MR_COUNT = 0         # constant defined on main Object class
module Foo
   MR_COUNT = 0
   ::MR_COUNT = 1    # set global count to 1
   MR_COUNT = 2      # set local count to 2
end
puts MR_COUNT        # this is the global constant
puts Foo::MR_COUNT   # this is the local "Foo" constant

第二個示例

CONST = ' out there'
class Inside_one
   CONST = proc {' in there'}
   def where_is_my_CONST
      ::CONST + ' inside one'
   end
end
class Inside_two
   CONST = ' inside two'
   def where_is_my_CONST
      CONST
   end
end
puts Inside_one.new.where_is_my_CONST
puts Inside_two.new.where_is_my_CONST
puts Object::CONST + Inside_two::CONST
puts Inside_two::CONST + CONST
puts Inside_one::CONST
puts Inside_one::CONST.call + Inside_two::CONST

Ruby 運算子優先順序

下表列出了所有運算子,從最高優先順序到最低優先順序。

方法 運算子 描述
:: 常量解析運算子
[ ] [ ]= 元素引用、元素設定
** 指數(乘方)
! ~ + - 非、補碼、一元加號和減號(後兩者的方法名稱為 +@ 和 -@)
* / % 乘、除和取模
+ - 加法和減法
>> << 右移和左移
& 按位“AND”
^ | 按位異或“OR”和常規“OR”
<= < > >= 比較運算子
<=> == === != =~ !~ 相等性和模式匹配運算子(!= 和 !~ 可能未定義為方法)
  && 邏輯“AND”
  || 邏輯“OR”
  .. ... 範圍(包含和排除)
  三元 if-then-else
  = %= { /= -= += |= &= >>= <<= *= &&= ||= **= 賦值
  defined? 檢查指定的符號是否已定義
  not 邏輯否定
  or 和 邏輯組合

注意 − 方法列中為“是”的運算子實際上是方法,因此可以被覆蓋。

Ruby - 註釋

註釋是在 Ruby 程式碼中執行時被忽略的批註行。單行註釋以 # 字元開頭,並從 # 擴充套件到行尾,如下所示 −

即時演示
#!/usr/bin/ruby -w
# This is a single line comment.

puts "Hello, Ruby!"

執行上述程式時,將產生以下結果 −

Hello, Ruby!

Ruby 多行註釋

您可以使用 =begin=end 語法註釋多行,如下所示 −

即時演示
#!/usr/bin/ruby -w

puts "Hello, Ruby!"

=begin
This is a multiline comment and con spwan as many lines as you
like. But =begin and =end should come in the first line only. 
=end

執行上述程式時,將產生以下結果 −

Hello, Ruby!

確保尾隨註釋與程式碼之間留有足夠的間距,並且易於區分。如果一個程式碼塊中存在多個尾隨註釋,則應將其對齊。例如:

@counter      # keeps track times page has been hit
@siteCounter  # keeps track of times all pages have been hit

Ruby - if...else、case、unless

Ruby 提供了在現代語言中相當常見的條件結構。在這裡,我們將解釋 Ruby 中所有可用的條件語句和修飾符。

Ruby if...else 語句

語法

if conditional [then]
   code...
[elsif conditional [then]
   code...]...
[else
   code...]
end

if 表示式用於條件執行。falsenil 的值為假,其他所有值都為真。請注意,Ruby 使用 elsif,而不是 else if 或 elif。

如果 條件 為真,則執行 程式碼。如果 條件 不為真,則執行 else 子句中指定的 程式碼

if 表示式的 條件 與程式碼之間用保留字 then、換行符或分號分隔。

示例

即時演示
#!/usr/bin/ruby

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
x is 1

Ruby if 修飾符

語法

code if condition

如果 條件 為真,則執行 程式碼

示例

即時演示
#!/usr/bin/ruby

$debug = 1
print "debug\n" if $debug

這將產生以下結果:

debug

Ruby unless 語句

語法

unless conditional [then]
   code
[else
   code ]
end

如果 條件 為假,則執行 程式碼。如果 條件 為真,則執行 else 子句中指定的程式碼。

示例

即時演示
#!/usr/bin/ruby

x = 1 
unless x>=2
   puts "x is less than 2"
 else
   puts "x is greater than 2"
end

這將產生以下結果:

x is less than 2

Ruby unless 修飾符

語法

code unless conditional

如果 條件 為假,則執行 程式碼

示例

即時演示
#!/usr/bin/ruby

$var =  1
print "1 -- Value is set\n" if $var
print "2 -- Value is set\n" unless $var

$var = false
print "3 -- Value is set\n" unless $var

這將產生以下結果:

1 -- Value is set
3 -- Value is set

Ruby case 語句

語法

case expression
[when expression [, expression ...] [then]
   code ]...
[else
   code ]
end

使用 === 運算子比較 case 指定的 表示式 和 when 指定的 表示式,並執行與之匹配的 when 子句的 程式碼

when 子句指定的 表示式 作為左運算元進行評估。如果沒有任何 when 子句匹配,則 case 執行 else 子句的程式碼。

when 語句的表示式與程式碼之間用保留字 then、換行符或分號分隔。因此:

case expr0
when expr1, expr2
   stmt1
when expr3, expr4
   stmt2
else
   stmt3
end

基本上類似於以下內容:

_tmp = expr0
if expr1 === _tmp || expr2 === _tmp
   stmt1
elsif expr3 === _tmp || expr4 === _tmp
   stmt2
else
   stmt3
end

示例

即時演示
#!/usr/bin/ruby

$age =  5
case $age
when 0 .. 2
   puts "baby"
when 3 .. 6
   puts "little child"
when 7 .. 12
   puts "child"
when 13 .. 18
   puts "youth"
else
   puts "adult"
end

這將產生以下結果:

little child

Ruby - 迴圈

Ruby 中的迴圈用於執行相同的程式碼塊指定的次數。本章詳細介紹了 Ruby 支援的所有迴圈語句。

Ruby while 語句

語法

while conditional [do]
   code
end

條件 為真時執行 程式碼while 迴圈的 條件程式碼 之間用保留字 do、換行符、反斜槓 \ 或分號 ; 分隔。

示例

即時演示
#!/usr/bin/ruby

$i = 0
$num = 5

while $i < $num  do
   puts("Inside the loop i = #$i" )
   $i +=1
end

這將產生以下結果:

Inside the loop i = 0
Inside the loop i = 1
Inside the loop i = 2
Inside the loop i = 3
Inside the loop i = 4

Ruby while 修飾符

語法

code while condition

OR

begin 
  code 
end while conditional

條件 為真時執行 程式碼

如果 while 修飾符跟隨 begin 語句,並且沒有 rescue 或 ensure 子句,則在評估條件之前會執行一次 程式碼

示例

即時演示
#!/usr/bin/ruby

$i = 0
$num = 5
begin
   puts("Inside the loop i = #$i" )
   $i +=1
end while $i < $num

這將產生以下結果:

Inside the loop i = 0
Inside the loop i = 1
Inside the loop i = 2
Inside the loop i = 3
Inside the loop i = 4

Ruby until 語句

until conditional [do]
   code
end

條件 為假時執行 程式碼until 語句的條件與程式碼之間用保留字 do、換行符或分號分隔。

示例

即時演示
#!/usr/bin/ruby

$i = 0
$num = 5

until $i > $num  do
   puts("Inside the loop i = #$i" )
   $i +=1;
end

這將產生以下結果:

Inside the loop i = 0
Inside the loop i = 1
Inside the loop i = 2
Inside the loop i = 3
Inside the loop i = 4
Inside the loop i = 5

Ruby until 修飾符

語法

code until conditional

OR

begin
   code
end until conditional

條件 為假時執行 程式碼

如果 until 修飾符跟隨 begin 語句,並且沒有 rescue 或 ensure 子句,則在評估條件之前會執行一次 程式碼

示例

即時演示
#!/usr/bin/ruby

$i = 0
$num = 5
begin
   puts("Inside the loop i = #$i" )
   $i +=1;
end until $i > $num

這將產生以下結果:

Inside the loop i = 0
Inside the loop i = 1
Inside the loop i = 2
Inside the loop i = 3
Inside the loop i = 4
Inside the loop i = 5

Ruby for 語句

語法

for variable [, variable ...] in expression [do]
   code
end

表示式 中的每個元素執行一次 程式碼

示例

即時演示
#!/usr/bin/ruby

for i in 0..5
   puts "Value of local variable is #{i}"
end

在這裡,我們定義了範圍 0..5。語句 for i in 0..5 將允許 i 取 0 到 5(包括 5)範圍內的值。這將產生以下結果:

Value of local variable is 0
Value of local variable is 1
Value of local variable is 2
Value of local variable is 3
Value of local variable is 4
Value of local variable is 5

for...in 迴圈幾乎完全等效於以下內容:

(expression).each do |variable[, variable...]| code end

除了 for 迴圈不會為區域性變數建立新的作用域之外。for 迴圈的 表示式程式碼 之間用保留字 do、換行符或分號分隔。

示例

即時演示
#!/usr/bin/ruby

(0..5).each do |i|
   puts "Value of local variable is #{i}"
end

這將產生以下結果:

Value of local variable is 0
Value of local variable is 1
Value of local variable is 2
Value of local variable is 3
Value of local variable is 4
Value of local variable is 5

Ruby break 語句

語法

break

終止最內部的迴圈。如果在塊內呼叫(方法返回 nil),則終止與關聯塊關聯的方法。

示例

即時演示
#!/usr/bin/ruby

for i in 0..5
   if i > 2 then
      break
   end
   puts "Value of local variable is #{i}"
end

這將產生以下結果:

Value of local variable is 0
Value of local variable is 1
Value of local variable is 2

Ruby next 語句

語法

next

跳到最內部迴圈的下一個迭代。如果在塊內呼叫(yield 或呼叫返回 nil),則終止塊的執行。

示例

即時演示
#!/usr/bin/ruby

for i in 0..5
   if i < 2 then
      next
   end
   puts "Value of local variable is #{i}"
end

這將產生以下結果:

Value of local variable is 2
Value of local variable is 3
Value of local variable is 4
Value of local variable is 5

Ruby redo 語句

語法

redo

重新啟動最內部迴圈的此迭代,而不檢查迴圈條件。如果在塊內呼叫,則重新啟動 yieldcall

示例

#!/usr/bin/ruby

for i in 0..5
   if i < 2 then
      puts "Value of local variable is #{i}"
      redo
   end
end

這將產生以下結果,並將進入無限迴圈:

Value of local variable is 0
Value of local variable is 0
............................

Ruby retry 語句

語法

retry

如果 retry 出現在 begin 表示式的 rescue 子句中,則從 begin 主體的開頭重新開始。

begin
   do_something # exception raised
rescue
   # handles error
   retry  # restart from beginning
end

如果 retry 出現在迭代器、塊或 for 表示式的正文中,則重新啟動迭代器呼叫的呼叫。迭代器的引數將重新評估。

for i in 1..5
   retry if some_condition # restart from i == 1
end

示例

#!/usr/bin/ruby
for i in 0..5
   retry if i > 2
puts "Value of local variable is #{i}"
end

這將產生以下結果,並將進入無限迴圈:

Value of local variable is 1
Value of local variable is 2
Value of local variable is 1
Value of local variable is 2
Value of local variable is 1
Value of local variable is 2
............................

Ruby - 方法

Ruby 方法與任何其他程式語言中的函式非常相似。Ruby 方法用於將一個或多個可重複語句捆綁到一個單元中。

方法名稱應以小寫字母開頭。如果使用方法名稱以大寫字母開頭,Ruby 可能會認為它是一個常量,因此可能會錯誤地解析呼叫。

應在呼叫方法之前定義方法,否則 Ruby 將引發未定義方法呼叫的異常。

語法

def method_name [( [arg [= default]]...[, * arg [, &expr ]])]
   expr..
end

因此,您可以按如下方式定義一個簡單的方法:

def method_name 
   expr..
end

您可以這樣表示接受引數的方法:

def method_name (var1, var2)
   expr..
end

您可以為引數設定預設值,如果在不傳遞所需引數的情況下呼叫方法,則將使用這些預設值:

def method_name (var1 = value1, var2 = value2)
   expr..
end

無論何時呼叫簡單方法,都只需編寫方法名稱,如下所示:

method_name

但是,當您使用方法和引數呼叫方法時,您需要編寫方法名稱以及引數,例如:

method_name 25, 30

使用帶引數的方法最重要的缺點是,無論何時呼叫此類方法,都需要記住引數的數量。例如,如果一個方法接受三個引數,而您只傳遞了兩個,則 Ruby 會顯示錯誤。

示例

即時演示
#!/usr/bin/ruby

def test(a1 = "Ruby", a2 = "Perl")
   puts "The programming language is #{a1}"
   puts "The programming language is #{a2}"
end
test "C", "C++"
test

這將產生以下結果:

The programming language is C
The programming language is C++
The programming language is Ruby
The programming language is Perl

方法的返回值

Ruby 中的每個方法預設都返回一個值。此返回值將是最後一條語句的值。例如:

def test
   i = 100
   j = 10
   k = 0
end

此方法在被呼叫時將返回最後宣告的變數 k

Ruby return 語句

ruby 中的 return 語句用於從 Ruby 方法返回一個或多個值。

語法

return [expr[`,' expr...]]

如果給出了兩個以上的表示式,則包含這些值的陣列將是返回值。如果沒有給出表示式,則 nil 將是返回值。

示例

return

OR

return 12

OR

return 1,2,3

請檢視此示例:

即時演示
#!/usr/bin/ruby

def test
   i = 100
   j = 200
   k = 300
return i, j, k
end
var = test
puts var

這將產生以下結果:

100
200
300

可變數量的引數

假設您宣告一個接受兩個引數的方法,無論何時呼叫此方法,都需要同時傳遞兩個引數。

但是,Ruby 允許您宣告可以使用可變數量的引數的方法。讓我們檢查一下這個示例:

即時演示
#!/usr/bin/ruby

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"

在此程式碼中,您聲明瞭一個接受一個引數 test 的方法 sample。但是,此引數是一個可變引數。這意味著此引數可以接收任意數量的變數。因此,以上程式碼將產生以下結果:

The number of parameters is 3
The parameters are Zara
The parameters are 6
The parameters are F
The number of parameters is 4
The parameters are Mac
The parameters are 36
The parameters are M
The parameters are MCA

類方法

當在類定義之外定義方法時,預設情況下該方法被標記為 private。另一方面,在類定義中定義的方法預設標記為 public。方法的預設可見性和 private 標記可以透過模組的 publicprivate 進行更改。

無論何時要訪問類的某個方法,都需要先例項化該類。然後,使用該物件,您可以訪問類的任何成員。

Ruby 提供了一種無需例項化類即可訪問方法的方式。讓我們看看如何宣告和訪問類方法:

class Accounts
   def reading_charge
   end
   def Accounts.return_date
   end
end

請參閱方法 return_date 的宣告方式。它以類名稱後跟一個點宣告,後跟方法名稱。您可以直接訪問此類方法,如下所示:

Accounts.return_date

要訪問此方法,您無需建立 Accounts 類的物件。

Ruby alias 語句

這為方法或全域性變數提供別名。別名不能在方法體內定義。即使方法被覆蓋,方法的別名也會保留方法的當前定義。

禁止為編號的全域性變數($1、$2 等)建立別名。覆蓋內建全域性變數可能會導致嚴重問題。

語法

alias method-name method-name
alias global-variable-name global-variable-name

示例

alias foo bar
alias $MATCH $&

在這裡,我們為 bar 定義了 foo 別名,而 $MATCH 是 $& 的別名。

Ruby undef 語句

這取消了方法定義。undef 不能出現在方法體內。

透過使用 undefalias,可以獨立於超類修改類的介面,但請注意,它可能會因對 self 的內部方法呼叫而破壞程式。

語法

undef method-name

示例

要取消定義名為 bar 的方法,請執行以下操作:

undef bar

Ruby - 程式碼塊

您已經瞭解了 Ruby 如何定義方法,您可以在其中放置多個語句,然後呼叫該方法。同樣,Ruby 也有一個塊的概念。

  • 塊由程式碼塊組成。

  • 您為塊分配一個名稱。

  • 塊中的程式碼始終括在括號 ({}) 內。

  • 塊始終從與塊名稱相同的函式中呼叫。這意味著,如果您有一個名為 test 的塊,那麼您將使用函式 test 來呼叫此塊。

  • 您可以使用 yield 語句呼叫塊。

語法

block_name {
   statement1
   statement2
   ..........
}

在這裡,您將學習如何使用簡單的 yield 語句呼叫塊。您還將學習如何使用方法帶引數的 yield 語句來呼叫塊。您將使用這兩種型別的 yield 語句檢查示例程式碼。

yield 語句

讓我們看一個 yield 語句的示例:

即時演示
#!/usr/bin/ruby

def test
   puts "You are in the method"
   yield
   puts "You are again back to the method"
   yield
end
test {puts "You are in the block"}

這將產生以下結果:

You are in the method
You are in the block
You are again back to the method
You are in the block

您還可以使用 yield 語句傳遞引數。這是一個示例:

即時演示
#!/usr/bin/ruby

def test
   yield 5
   puts "You are in the method test"
   yield 100
end
test {|i| puts "You are in the block #{i}"}

這將產生以下結果:

You are in the block 5
You are in the method test
You are in the block 100

在這裡,yield 語句後跟引數。您甚至可以傳遞多個引數。在塊中,您在兩個垂直線 (||) 之間放置一個變數來接收引數。因此,在前面的程式碼中,yield 5 語句將值 5 作為引數傳遞給 test 塊。

現在,看看以下語句:

test {|i| puts "You are in the block #{i}"}

在這裡,值 5 將被接收在變數 i 中。現在,觀察以下 puts 語句:

puts "You are in the block #{i}"

puts 語句的輸出為:

You are in the block 5

如果要傳遞多個引數,則 yield 語句變為:

yield a, b

並且塊為:

test {|a, b| statement}

引數將用逗號分隔。

塊和方法

您已經瞭解了塊和方法如何相互關聯。您通常使用 yield 語句從與塊名稱相同的名稱的方法中呼叫塊。因此,您編寫:

即時演示
#!/usr/bin/ruby

def test
   yield
end
test{ puts "Hello world"}

此示例是實現塊的最簡單方法。您使用 yield 語句呼叫 test 塊。

但是,如果方法的最後一個引數前面有 &,則可以將塊傳遞給此方法,並且此塊將分配給最後一個引數。如果 * 和 & 都出現在引數列表中,則 & 應放在後面。

即時演示
#!/usr/bin/ruby

def test(&block)
   block.call
end
test { puts "Hello World!"}

這將產生以下結果:

Hello World!

BEGIN 和 END 塊

每個 Ruby 原始檔都可以宣告程式碼塊,以便在載入檔案時(BEGIN 塊)和程式執行完成後(END 塊)執行。

即時演示
#!/usr/bin/ruby

BEGIN { 
   # BEGIN block code 
   puts "BEGIN code block"
} 

END { 
   # END block code 
   puts "END code block"
}
   # MAIN block code 
puts "MAIN code block"

程式可能包含多個 BEGIN 和 END 塊。BEGIN 塊按遇到的順序執行。END 塊以相反的順序執行。執行時,上述程式產生以下結果:

BEGIN code block
MAIN code block
END code block

Ruby - 模組和 Mixin

模組是將方法、類和常量組合在一起的一種方式。模組為您提供了兩個主要好處。

  • 模組提供 名稱空間 並防止名稱衝突。

  • 模組實現 mixin 功能。

模組定義了一個名稱空間,一個沙盒,您的方法和常量可以在其中執行,而無需擔心會被其他方法和常量覆蓋。

語法

module Identifier
   statement1
   statement2
   ...........
end

模組常量的命名方式與類常量相同,都以大寫字母開頭。方法定義也類似:模組方法的定義方式與類方法相同。

與類方法一樣,您可以透過在方法名稱前面加上模組名稱和一個點來呼叫模組方法,並且您可以使用模組名稱和兩個冒號來引用常量。

示例

#!/usr/bin/ruby

# Module defined in trig.rb file

module Trig
   PI = 3.141592654
   def Trig.sin(x)
   # ..
   end
   def Trig.cos(x)
   # ..
   end
end

我們可以使用相同函式名稱但功能不同的方式定義另一個模組:

#!/usr/bin/ruby

# Module defined in moral.rb file

module Moral
   VERY_BAD = 0
   BAD = 1
   def Moral.sin(badness)
   # ...
   end
end

與類方法一樣,無論何時在模組中定義方法,都需要指定模組名稱,後跟一個點,然後是方法名稱。

Ruby require 語句

require 語句類似於 C 和 C++ 的 include 語句以及 Java 的 import 語句。如果第三個程式想要使用任何已定義的模組,它只需使用 Ruby 的require語句載入模組檔案即可。

語法

require filename

這裡,不需要在檔名後面加上.rb副檔名。

示例

$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從相對目錄包含檔案。

重要 - 這裡,兩個檔案都包含相同的函式名。因此,這會導致在呼叫程式中包含時出現程式碼歧義,但模組避免了這種程式碼歧義,並且我們能夠使用模組名稱呼叫相應的函式。

Ruby include 語句

您可以在類中嵌入模組。要在類中嵌入模組,請在類中使用include語句。

語法

include modulename

如果模組在單獨的檔案中定義,則在將模組嵌入類之前,需要使用require語句包含該檔案。

示例

考慮以下在support.rb檔案中編寫的模組。

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

現在,您可以按如下方式將此模組包含在類中:

#!/usr/bin/ruby
$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

這將產生以下結果:

Sunday
You have four weeks in a month
You have 52 weeks in a year
Sunday
120

Ruby 中的 Mixin

在閱讀本節之前,我們假設您已瞭解面向物件的概念。

當一個類可以從多個父類繼承特性時,該類應該表現出多重繼承。

Ruby 不直接支援多重繼承,但 Ruby 模組還有另一個奇妙的用途。一舉解決了對多重繼承的需求,提供了一種稱為mixin的功能。

Mixin 為您提供了一種極佳的控制方式來向類新增功能。但是,當 mixin 中的程式碼開始與使用它的類中的程式碼互動時,它們真正的力量就會顯現出來。

讓我們檢查以下示例程式碼以瞭解 mixin:

module A
   def a1
   end
   def a2
   end
end
module B
   def b1
   end
   def b2
   end
end

class Sample
include A
include B
   def s1
   end
end

samp = Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1

模組 A 包含方法 a1 和 a2。模組 B 包含方法 b1 和 b2。類 Sample 包含模組 A 和 B。類 Sample 可以訪問所有四個方法,即 a1、a2、b1 和 b2。因此,您可以看到類 Sample 從這兩個模組繼承。因此,您可以說類 Sample 顯示了多重繼承或mixin

Ruby - 字串

Ruby 中的字串物件儲存和操作一個或多個位元組的任意序列,通常表示代表人類語言的字元。

最簡單的字串字面量用單引號(撇號字元)括起來。引號內的文字是字串的值。

'This is a simple Ruby string literal'

如果需要在單引號字串字面量中放置撇號,請在其前面加上反斜槓,以便 Ruby 直譯器不會認為它終止了字串。

'Won\'t you read O\'Reilly\'s book?'

反斜槓也可用於轉義另一個反斜槓,以便第二個反斜槓本身不被解釋為跳脫字元。

以下是 Ruby 中與字串相關的功能。

表示式替換

表示式替換是一種使用 #{ 和 } 將任何 Ruby 表示式的值嵌入到字串中的方法。

即時演示
#!/usr/bin/ruby

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 }."

這將產生以下結果:

The value of x is 12.
The sum of x and y is 48.
The average was 40.

通用分隔字串

使用通用分隔字串,您可以在一對匹配的任意分隔符字元(例如!、(、{、< 等)內建立字串,這些字元前面是百分號字元 (%)。Q、q 和 x 具有特殊含義。通用分隔字串可以是:

%{Ruby is fun.}  equivalent to "Ruby is fun."
%Q{ Ruby is fun. } equivalent to " Ruby is fun. "
%q[Ruby is fun.]  equivalent to a single-quoted string
%x!ls! equivalent to back tick command output `ls`

跳脫字元

字元編碼

Ruby 的預設字元集是 ASCII,其字元可以用單個位元組表示。如果您使用 UTF-8 或其他現代字元集,則字元可以用 1 到 4 個位元組表示。

您可以在程式開頭使用 $KCODE 更改字元集,如下所示:

$KCODE = 'u'

字串內建方法

我們需要有一個字串物件的例項才能呼叫字串方法。以下是建立字串物件例項的方法:

new [String.new(str = "")]

這將返回一個新的字串物件,其中包含str的副本。現在,使用str物件,我們可以使用任何可用的例項方法。例如:

即時演示
#!/usr/bin/ruby

myStr = String.new("THIS IS TEST")
foo = myStr.downcase

puts "#{foo}"

這將產生以下結果:

this is test

String 解包指令

示例

嘗試以下示例以解包各種資料。

"abc \0\0abc \0\0".unpack('A6Z6')   #=> ["abc", "abc "]
"abc \0\0".unpack('a3a3')           #=> ["abc", " \000\000"]
"abc \0abc \0".unpack('Z*Z*')       #=> ["abc ", "abc "]
"aa".unpack('b8B8')                 #=> ["10000110", "01100001"]
"aaa".unpack('h2H2c')               #=> ["16", "61", 97]
"\xfe\xff\xfe\xff".unpack('sS')     #=> [-2, 65534]
"now = 20is".unpack('M*')           #=> ["now is"]
"whole".unpack('xax2aX2aX1aX2a')    #=> ["h", "e", "l", "l", "o"]

Ruby - 陣列

Ruby 陣列是有序的、整數索引的任何物件的集合。陣列中的每個元素都與一個索引相關聯並由其引用。

陣列索引從 0 開始,如 C 或 Java 中一樣。負索引假定相對於陣列的末尾——即,索引 -1 指示陣列的最後一個元素,-2 是陣列的倒數第二個元素,依此類推。

Ruby 陣列可以儲存各種物件,例如字串 (String)、整數 (Integer)、Fixnum、雜湊 (Hash)、符號 (Symbol),甚至其他陣列物件。Ruby 陣列不像其他語言中的陣列那樣嚴格。在向 Ruby 陣列新增元素時,它會自動增長。

建立陣列

有很多方法可以建立或初始化陣列。其中一種方法是使用 new 類方法 -

names = Array.new

您可以在建立陣列時設定陣列的大小 -

names = Array.new(20)

陣列 names 現在具有 20 個元素的大小或長度。您可以使用 size 或 length 方法返回陣列的大小 -

即時演示
#!/usr/bin/ruby

names = Array.new(20)
puts names.size  # This returns 20
puts names.length # This also returns 20

這將產生以下結果:

20
20

您可以如下為陣列中的每個元素分配一個值 -

即時演示
#!/usr/bin/ruby

names = Array.new(4, "mac")
puts "#{names}"

這將產生以下結果:

["mac", "mac", "mac", "mac"]

您還可以使用帶 new 的程式碼塊,用程式碼塊計算出的結果填充每個元素 -

即時演示
#!/usr/bin/ruby

nums = Array.new(10) { |e| e = e * 2 }
puts "#{nums}"

這將產生以下結果:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

陣列還有另一種方法,即 []。它的工作方式如下 -

nums = Array.[](1, 2, 3, 4,5)

陣列建立的另一種形式如下 -

nums = Array[1, 2, 3, 4,5]

核心 Ruby 中可用的 Kernel 模組有一個 Array 方法,它只接受一個引數。在這裡,該方法將範圍作為引數來建立一個數字陣列 -

即時演示
#!/usr/bin/ruby

digits = Array(0..9)
puts "#{digits}"

這將產生以下結果:

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

陣列內建方法

我們需要有一個 Array 物件的例項才能呼叫 Array 方法。正如我們所見,以下是建立 Array 物件例項的方法 -

Array.[](...) [or] Array[...] [or] [...]

這將返回一個使用給定物件填充的新陣列。現在,使用建立的物件,我們可以呼叫任何可用的例項方法。例如 -

即時演示
#!/usr/bin/ruby

digits = Array(0..9)
num = digits.at(6)
puts "#{num}"

這將產生以下結果:

6

Array pack 指令

示例

嘗試以下示例來打包各種資料。

即時演示
a = [ "a", "b", "c" ]
n = [ 65, 66, 67 ]
puts a.pack("A3A3A3")   #=> "a  b  c  "
puts a.pack("a3a3a3")   #=> "a\000\000b\000\000c\000\000"
puts n.pack("ccc")      #=> "ABC"

這將產生以下結果:

a  b  c
abc
ABC

Ruby - 雜湊表

Hash是一個鍵值對的集合,例如:"employee" => "salary"。它類似於陣列,但索引是透過任何物件型別的任意鍵完成的,而不是整數索引。

透過鍵或值遍歷雜湊的順序可能看起來是任意的,並且通常不會按插入順序排列。如果您嘗試使用不存在的鍵訪問雜湊,則該方法將返回nil

建立雜湊

與陣列一樣,建立雜湊有多種方法。您可以使用new類方法建立空雜湊 -

months = Hash.new

您還可以使用new建立具有預設值的雜湊,否則預設為nil -

months = Hash.new( "month" )

or

months = Hash.new "month"

當您訪問具有預設值的雜湊中的任何鍵時,如果鍵或值不存在,訪問雜湊將返回預設值 -

即時演示
#!/usr/bin/ruby

months = Hash.new( "month" )

puts "#{months[0]}"
puts "#{months[72]}"

這將產生以下結果:

month
month

即時演示
#!/usr/bin/ruby

H = Hash["a" => 100, "b" => 200]

puts "#{H['a']}"
puts "#{H['b']}"

這將產生以下結果:

100
200

您可以使用任何Ruby物件作為鍵或值,甚至陣列,因此以下示例是有效的 -

[1,"jan"] => "January"

Hash內建方法

我們需要有一個Hash物件的例項才能呼叫Hash方法。正如我們所見,以下是建立Hash物件例項的方法 -

Hash[[key =>|, value]* ] or

Hash.new [or] Hash.new(obj) [or]
Hash.new { |hash, key| block }

這將返回一個使用給定物件填充的新雜湊。現在使用建立的物件,我們可以呼叫任何可用的例項方法。例如 -

即時演示
#!/usr/bin/ruby

$, = ", "
months = Hash.new( "month" )
months = {"1" => "January", "2" => "February"}

keys = months.keys
puts "#{keys}"

這將產生以下結果:

["1", "2"]

以下是公共雜湊方法(假設hash是陣列物件) -

序號 方法和描述
1

hash == other_hash

測試兩個雜湊是否相等,基於它們是否具有相同數量的鍵值對,以及鍵值對是否與每個雜湊中的對應對匹配。

2

hash.[key]

使用鍵從雜湊中引用值。如果找不到鍵,則返回預設值。

3

hash.[key] = value

value給出的值與key給出的鍵關聯。

4

hash.clear

從雜湊中移除所有鍵值對。

5

hash.default(key = nil)

返回hash的預設值,如果未由default=設定則返回nil。([]如果鍵不存在於hash中,則返回預設值。)

6

hash.default = obj

設定hash的預設值。

7

hash.default_proc

如果hash是由塊建立的,則返回一個塊。

8

hash.delete(key) [或]

array.delete(key) { |key| block }

透過keyhash中刪除鍵值對。如果使用塊,則如果未找到對則返回塊的結果。比較delete_if

9

hash.delete_if { |key,value| block }

對於塊計算結果為true的每個對,從hash中刪除鍵值對。

10

hash.each { |key,value| block }

迭代hash,為每個鍵呼叫塊一次,並將鍵值作為兩個元素的陣列傳遞。

11

hash.each_key { |key| block }

迭代hash,為每個鍵呼叫塊一次,並將key作為引數傳遞。

12

hash.each_key { |key_value_array| block }

迭代hash,為每個key呼叫塊一次,並將keyvalue作為引數傳遞。

13

hash.each_key { |value| block }

迭代hash,為每個key呼叫塊一次,並將value作為引數傳遞。

14

hash.empty?

測試雜湊是否為空(不包含任何鍵值對),返回truefalse

15

hash.fetch(key [, default] ) [或]

hash.fetch(key) { | key | block }

hash中返回給定key的值。如果找不到key,並且沒有其他引數,則引發IndexError異常;如果給出了default,則返回它;如果指定了可選塊,則返回其結果。

16

hash.has_key?(key) [或] hash.include?(key) [或]

hash.key?(key) [或] hash.member?(key)

測試給定的key是否出現在雜湊中,返回truefalse

17

hash.has_value?(value)

測試雜湊是否包含給定的value

18

hash.index(value)

返回雜湊中給定valuekey,如果未找到匹配的值則返回nil

19

hash.indexes(keys)

返回一個新陣列,其中包含給定鍵的值。將為未找到的鍵插入預設值。此方法已棄用。使用select。

20

hash.indices(keys)

返回一個新陣列,其中包含給定鍵的值。將為未找到的鍵插入預設值。此方法已棄用。使用select。

21

hash.inspect

返回雜湊的漂亮列印字串版本。

22

hash.invert

建立一個新的hash,反轉hash中的keysvalues;也就是說,在新雜湊中,hash中的鍵變為值,值變為鍵。

23

hash.keys

建立一個包含hash中鍵的新陣列。

24

hash.length

返回hash的大小或長度,作為一個整數。

25

hash.merge(other_hash) [或]

hash.merge(other_hash) { |key, oldval, newval| block }

返回一個新雜湊,其中包含hashother_hash的內容,用other_hash中的內容覆蓋hash中具有重複鍵的對。

26

hash.merge!(other_hash) [或]

hash.merge!(other_hash) { |key, oldval, newval| block }

與merge相同,但更改是在原地進行的。

27

hash.rehash

根據每個key的當前值重建hash。如果值自插入以來已更改,則此方法會重新索引hash

28

hash.reject { |key, value| block }

block計算結果為true的每個對建立一個新的hash

29

hash.reject! { |key, value| block }

reject相同,但更改是在原地進行的。

30

hash.replace(other_hash)

other_hash的內容替換hash的內容。

31

hash.select { |key, value| block }

返回一個新陣列,其中包含hashblock返回true的鍵值對。

32

hash.shift

hash中移除鍵值對,並將其作為兩個元素的陣列返回。

33

hash.size

返回hash的大小或長度,作為一個整數。

34

hash.sort

hash轉換為一個包含鍵值對陣列的二維陣列,然後將其作為陣列排序。

35

hash.store(key, value)

hash中儲存鍵值對。

36

hash.to_a

從雜湊建立二維陣列。每個鍵/值對都轉換為陣列,所有這些陣列都儲存在一個包含陣列中。

37

hash.to_hash

返回hash(self)。

38

hash.to_s

hash轉換為陣列,然後將該陣列轉換為字串。

39

hash.update(other_hash) [或]

hash.update(other_hash) {|key, oldval, newval| block}

返回一個新雜湊,其中包含hashother_hash的內容,用other_hash中的內容覆蓋hash中具有重複鍵的對。

40

hash.value?(value)

測試hash是否包含給定的value

41

hash.values

返回一個包含hash所有值的新陣列。

42

hash.values_at(obj, ...)

返回一個新陣列,其中包含與給定鍵或鍵關聯的hash中的值。

Ruby - 日期和時間

Time 類表示 Ruby 中的日期和時間。它是在作業系統提供的系統日期和時間功能之上的一層薄薄的封裝。此類可能無法在您的系統上表示 1970 年之前或 2038 年之後的日期。

本章使您熟悉日期和時間的所有最需要的概念。

獲取當前日期和時間

以下是獲取當前日期和時間的簡單示例:

即時演示
#!/usr/bin/ruby -w

time1 = Time.new
puts "Current Time : " + time1.inspect

# Time.now is a synonym:
time2 = Time.now
puts "Current Time : " + time2.inspect

這將產生以下結果:

Current Time : Mon Jun 02 12:02:39 -0700 2008
Current Time : Mon Jun 02 12:02:39 -0700 2008

獲取日期和時間的組成部分

我們可以使用Time物件獲取日期和時間的各種組成部分。以下是顯示相同內容的示例:

即時演示
#!/usr/bin/ruby -w

time = Time.new

# Components of a Time
puts "Current Time : " + time.inspect
puts time.year    # => Year of the date 
puts time.month   # => Month of the date (1 to 12)
puts time.day     # => Day of the date (1 to 31 )
puts time.wday    # => 0: Day of week: 0 is Sunday
puts time.yday    # => 365: Day of year
puts time.hour    # => 23: 24-hour clock
puts time.min     # => 59
puts time.sec     # => 59
puts time.usec    # => 999999: microseconds
puts time.zone    # => "UTC": timezone name

這將產生以下結果:

Current Time : Mon Jun 02 12:03:08 -0700 2008
2008
6
2
1
154
12
3
8
247476
UTC

Time.utc、Time.gm 和 Time.local 函式

這兩個函式可用於如下格式化日期為標準格式:

# July 8, 2008
Time.local(2008, 7, 8)  
# July 8, 2008, 09:10am, local time
Time.local(2008, 7, 8, 9, 10)   
# July 8, 2008, 09:10 UTC
Time.utc(2008, 7, 8, 9, 10)  
# July 8, 2008, 09:10:11 GMT (same as UTC)
Time.gm(2008, 7, 8, 9, 10, 11)  

以下是如何以以下格式獲取陣列中所有元件的示例:

[sec,min,hour,day,month,year,wday,yday,isdst,zone]

嘗試以下操作:

即時演示
#!/usr/bin/ruby -w

time = Time.new
values = time.to_a
p values

這將生成以下結果:

[26, 10, 12, 2, 6, 2008, 1, 154, false, "MST"]

此陣列可以傳遞給Time.utcTime.local函式以獲取日期的不同格式,如下所示:

即時演示
#!/usr/bin/ruby -w

time = Time.new
values = time.to_a
puts Time.utc(*values)

這將生成以下結果:

Mon Jun 02 12:15:36 UTC 2008

以下是獲取自(平臺相關的)紀元以來以秒為單位表示的時間的方式:

# Returns number of seconds since epoch
time = Time.now.to_i  

# Convert number of seconds into Time object.
Time.at(time)

# Returns second since epoch which includes microseconds
time = Time.now.to_f

時區和夏令時

您可以使用Time物件獲取與時區和夏令時相關的所有資訊,如下所示:

time = Time.new

# Here is the interpretation
time.zone       # => "UTC": return the timezone
time.utc_offset # => 0: UTC is 0 seconds offset from UTC
time.zone       # => "PST" (or whatever your timezone is)
time.isdst      # => false: If UTC does not have DST.
time.utc?       # => true: if t is in UTC time zone
time.localtime  # Convert to local timezone.
time.gmtime     # Convert back to UTC.
time.getlocal   # Return a new Time object in local zone
time.getutc     # Return a new Time object in UTC

格式化時間和日期

有多種方法可以格式化日期和時間。以下是一個顯示一些示例:

即時演示
#!/usr/bin/ruby -w

time = Time.new
puts time.to_s
puts time.ctime
puts time.localtime
puts time.strftime("%Y-%m-%d %H:%M:%S")

這將產生以下結果:

Mon Jun 02 12:35:19 -0700 2008
Mon Jun  2 12:35:19 2008
Mon Jun 02 12:35:19 -0700 2008
2008-06-02 12:35:19

時間格式化指令

下表中的這些指令與Time.strftime方法一起使用。

序號 指令和描述
1

%a

縮寫的工作日名稱(Sun)。

2

%A

完整的工作日名稱(Sunday)。

3

%b

縮寫月份名稱(Jan)。

4

%B

完整月份名稱(January)。

5

%c

首選的本地日期和時間表示形式。

6

%d

月份中的日期(01 到 31)。

7

%H

一天中的小時,24 小時制(00 到 23)。

8

%I

一天中的小時,12 小時制(01 到 12)。

9

%j

一年中的日期(001 到 366)。

10

%m

一年中的月份(01 到 12)。

11

%M

小時中的分鐘(00 到 59)。

12

%p

子午線指示器(AM 或 PM)。

13

%S

分鐘中的秒(00 到 60)。

14

%U

當前年份的星期數,從第一個星期日作為第一週的第一天開始(00 到 53)。

15

%W

當前年份的星期數,從第一個星期一作為第一週的第一天開始(00 到 53)。

16

%w

一週中的某一天(星期日為 0,0 到 6)。

17

%x

僅日期的首選表示形式,沒有時間。

18

%X

僅時間首選表示形式,沒有日期。

19

%y

沒有世紀的年份(00 到 99)。

20

%Y

帶世紀的年份。

21

%Z

時區名稱。

22

%%

文字 % 字元。

時間算術

您可以對時間執行簡單的算術運算,如下所示:

即時演示
now = Time.now          # Current time
puts now

past = now - 10         # 10 seconds ago. Time - number => Time
puts past

future = now + 10  # 10 seconds from now Time + number => Time
puts future

diff = future - past     # => 10  Time - Time => number of seconds
puts diff

這將產生以下結果:

Thu Aug 01 20:57:05 -0700 2013
Thu Aug 01 20:56:55 -0700 2013
Thu Aug 01 20:57:15 -0700 2013
20.0

Ruby - 範圍

範圍無處不在:1 月到 12 月、0 到 9、第 50 行到第 67 行,等等。Ruby 支援範圍,並允許我們以各種方式使用範圍:

  • 範圍作為序列
  • 範圍作為條件
  • 範圍作為區間

範圍作為序列

範圍的第一個也是最自然的用途是表達一個序列。序列有起點、終點和生成序列中後續值的方法。

Ruby 使用''..''''...''範圍運算子建立這些序列。兩點形式建立包含範圍,而三點形式建立排除指定高值的範圍。

(1..5)        #==> 1, 2, 3, 4, 5
(1...5)       #==> 1, 2, 3, 4
('a'..'d')    #==> 'a', 'b', 'c', 'd'

序列 1..100 作為包含對兩個Fixnum物件引用的 Range 物件來儲存。如果需要,可以使用to_a方法將範圍轉換為列表。嘗試以下示例:

即時演示
#!/usr/bin/ruby

$, =", "   # Array value separator
range1 = (1..10).to_a
range2 = ('bar'..'bat').to_a

puts "#{range1}"
puts "#{range2}"

這將產生以下結果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
["bar", "bas", "bat"]

範圍實現允許您以各種方式迭代它們並測試其內容的方法:

即時演示
#!/usr/bin/ruby

# Assume a range
digits = 0..9

puts digits.include?(5)
ret = digits.min
puts "Min value is #{ret}"

ret = digits.max
puts "Max value is #{ret}"

ret = digits.reject {|i| i < 5 }
puts "Rejected values are #{ret}"

digits.each do |digit|
   puts "In Loop #{digit}"
end

這將產生以下結果:

true
Min value is 0
Max value is 9
Rejected values are 5, 6, 7, 8, 9
In Loop 0
In Loop 1
In Loop 2
In Loop 3
In Loop 4
In Loop 5
In Loop 6
In Loop 7
In Loop 8
In Loop 9

範圍作為條件

範圍也可以用作條件表示式。例如,以下程式碼片段列印來自標準輸入的行的集合,其中每個集合的第一行包含單詞start,最後一行包含單詞ends

while gets
   print if /start/../end/
end

範圍可用於 case 語句中:

即時演示
#!/usr/bin/ruby

score = 70

result = case score
   when 0..40 then "Fail"
   when 41..60 then "Pass"
   when 61..70 then "Pass with Merit"
   when 71..100 then "Pass with Distinction"
   else "Invalid Score"
end

puts result

這將產生以下結果:

Pass with Merit

範圍作為區間

多功能範圍的最終用途是作為區間測試:檢視某個值是否落在範圍表示的區間內。這是使用 ===(情況相等運算子)完成的。

即時演示
#!/usr/bin/ruby

if ((1..10) === 5)
   puts "5 lies in (1..10)"
end

if (('a'..'j') === 'c')
   puts "c lies in ('a'..'j')"
end

if (('a'..'j') === 'z')
   puts "z lies in ('a'..'j')"
end

這將產生以下結果:

5 lies in (1..10)
c lies in ('a'..'j')

Ruby - 迭代器

迭代器只不過是集合支援的方法。儲存一組資料成員的物件稱為集合。在 Ruby 中,陣列和雜湊可以稱為集合。

迭代器依次返回集合的所有元素。我們將在本文中討論兩個迭代器,eachcollect。讓我們詳細瞭解一下。

Ruby each 迭代器

each 迭代器返回陣列或雜湊的所有元素。

語法

collection.each do |variable|
   code
end

collection中的每個元素執行code。此處,collection可以是陣列或 Ruby 雜湊。

示例

即時演示
#!/usr/bin/ruby

ary = [1,2,3,4,5]
ary.each do |i|
   puts i
end

這將產生以下結果:

1
2
3
4
5

您始終將each迭代器與塊關聯。它將陣列的每個值逐個返回到塊中。該值儲存在變數i中,然後顯示在螢幕上。

Ruby collect 迭代器

collect迭代器返回集合的所有元素。

語法

collection = collection.collect

collect方法並不總是需要與塊關聯。collect方法返回整個集合,無論它是陣列還是雜湊。

示例

#!/usr/bin/ruby

a = [1,2,3,4,5]
b = Array.new
b = a.collect
puts b

這將產生以下結果:

1
2
3
4
5

注意 - collect方法不是在陣列之間進行復制的正確方法。還有另一種稱為clone的方法,應使用該方法將一個數組複製到另一個數組中。

當您希望對每個值執行某些操作以獲取新陣列時,通常使用 collect 方法。例如,此程式碼生成一個數組b,其中包含a中每個值的 10 倍。

即時演示
#!/usr/bin/ruby

a = [1,2,3,4,5]
b = a.collect{|x| 10*x}
puts b

這將產生以下結果:

10
20
30
40
50

Ruby - 檔案 I/O

Ruby 提供了一整套在 Kernel 模組中實現的與 I/O 相關的 方法。所有 I/O 方法都派生自 IO 類。

IO類提供所有基本方法,例如read、write、gets、puts、readline、getcprintf

本章將涵蓋 Ruby 中可用的所有基本 I/O 函式。有關更多函式,請參閱 Ruby 類IO

puts 語句

在前面的章節中,您已將值分配給變數,然後使用puts語句列印輸出。

puts語句指示程式顯示儲存在變數中的值。這將在它寫入的每一行的末尾新增一個新行。

示例

即時演示
#!/usr/bin/ruby

val1 = "This is variable one"
val2 = "This is variable two"
puts val1
puts val2

這將產生以下結果:

This is variable one
This is variable two

gets 語句

gets語句可用於從稱為 STDIN 的標準螢幕獲取使用者的任何輸入。

示例

以下程式碼向您展示瞭如何使用 gets 語句。此程式碼將提示使用者輸入一個值,該值將儲存在變數 val 中,最後將列印到 STDOUT。

#!/usr/bin/ruby

puts "Enter a value :"
val = gets
puts val

這將產生以下結果:

Enter a value :
This is entered value
This is entered value

putc 語句

與輸出整個字串到螢幕上的puts語句不同,putc語句可用於一次輸出一個字元。

示例

以下程式碼的輸出僅為字元 H:

即時演示
#!/usr/bin/ruby

str = "Hello Ruby!"
putc str

這將產生以下結果:

H

print 語句

print語句類似於puts語句。唯一的區別是puts語句在列印內容後換行,而print語句的游標位於同一行。

示例

即時演示
#!/usr/bin/ruby

print "Hello World"
print "Good Morning"

這將產生以下結果:

Hello WorldGood Morning

開啟和關閉檔案

到目前為止,您一直在讀取和寫入標準輸入和輸出。現在,我們將瞭解如何處理實際的資料檔案。

File.new 方法

您可以使用File.new方法建立一個File物件,用於讀取、寫入或同時進行讀取和寫入,具體取決於模式字串。最後,您可以使用File.close方法關閉該檔案。

語法

aFile = File.new("filename", "mode")
   # ... process the file
aFile.close

File.open 方法

您可以使用File.open方法建立一個新的檔案物件並將該檔案物件分配給一個檔案。但是,File.openFile.new方法之間存在一個區別。區別在於File.open方法可以與塊關聯,而您無法使用File.new方法執行相同的操作。

File.open("filename", "mode") do |aFile|
   # ... process the file
end

a+

讀寫模式。如果檔案存在,則檔案指標位於檔案末尾。檔案以追加模式開啟。如果檔案不存在,則建立一個新檔案以進行讀取和寫入。

讀取和寫入檔案

我們一直在使用的“簡單”I/O 的相同方法可用於所有檔案物件。因此,gets 從標準輸入讀取一行,而aFile.gets從檔案物件 aFile 讀取一行。

但是,I/O 物件提供了一組額外的訪問方法,使我們的生活更輕鬆。

sysread 方法

This is a simple text file for testing purpose.

您可以使用sysread方法讀取檔案的內容。在使用sysread方法時,您可以以任何模式開啟檔案。例如:

#!/usr/bin/ruby

aFile = File.new("input.txt", "r")
if aFile
   content = aFile.sysread(20)
   puts content
else
   puts "Unable to open file!"
end

此語句將輸出檔案的前 20 個字元。檔案指標現在將放置在檔案中的第 21 個字元處。

syswrite 方法

您可以使用 syswrite 方法將內容寫入檔案。使用 syswrite 方法時,需要以寫入模式開啟檔案。例如 -

#!/usr/bin/ruby

aFile = File.new("input.txt", "r+")
if aFile
   aFile.syswrite("ABCDEF")
else
   puts "Unable to open file!"
end

此語句將“ABCDEF”寫入檔案。

each_byte 方法

此方法屬於 File 類。each_byte 方法始終與一個程式碼塊關聯。請考慮以下程式碼示例 -

#!/usr/bin/ruby

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

字元逐個傳遞給變數 ch,然後按如下方式顯示在螢幕上 -

s. .a. .s.i.m.p.l.e. .t.e.x.t. .f.i.l.e. .f.o.r. .t.e.s.t.i.n.g. .p.u.r.p.o.s.e...
.
.

IO.readlines 方法

File 類是 IO 類的子類。IO 類也有一些方法,可用於操作檔案。

IO 類方法之一是 IO.readlines。此方法逐行返回檔案的內容。以下程式碼顯示了 IO.readlines 方法的使用 -

#!/usr/bin/ruby

arr = IO.readlines("input.txt")
puts arr[0]
puts arr[1]

在此程式碼中,變數 arr 是一個數組。input.txt 檔案的每一行都將是陣列 arr 中的一個元素。因此,arr[0] 將包含第一行,而 arr[1] 將包含檔案的第二行。

IO.foreach 方法

此方法也逐行返回輸出。foreach 方法和 readlines 方法的區別在於 foreach 方法與一個程式碼塊關聯。但是,與 readlines 方法不同,foreach 方法不返回陣列。例如 -

#!/usr/bin/ruby

IO.foreach("input.txt"){|block| puts block}

此程式碼將 test 檔案的內容逐行傳遞給變數 block,然後輸出將顯示在螢幕上。

重新命名和刪除檔案

您可以使用 Ruby 中的 renamedelete 方法以程式設計方式重新命名和刪除檔案。

以下是重新命名現有檔案 test1.txt 的示例 -

#!/usr/bin/ruby

# Rename a file from test1.txt to test2.txt
File.rename( "test1.txt", "test2.txt" )

以下是刪除現有檔案 test2.txt 的示例 -

#!/usr/bin/ruby

# Delete file test2.txt
File.delete("test2.txt")

檔案模式和所有權

使用帶掩碼的 chmod 方法更改檔案的模式或許可權/訪問列表 -

以下是將現有檔案 test.txt 的模式更改為掩碼值的示例 -

#!/usr/bin/ruby

file = File.new( "test.txt", "w" )
file.chmod( 0755 )

檔案查詢

以下命令在開啟檔案之前測試檔案是否存在 -

#!/usr/bin/ruby

File.open("file.rb") if File::exists?( "file.rb" )

以下命令查詢檔案是否真的是檔案 -

#!/usr/bin/ruby

# This returns either true or false
File.file?( "text.txt" ) 

以下命令查詢給定的檔名是否為目錄 -

#!/usr/bin/ruby

# a directory
File::directory?( "/usr/local/bin" ) # => true

# a file
File::directory?( "file.rb" ) # => false

以下命令查詢檔案是否可讀、可寫或可執行 -

#!/usr/bin/ruby

File.readable?( "test.txt" )   # => true
File.writable?( "test.txt" )   # => true
File.executable?( "test.txt" ) # => false

以下命令查詢檔案大小是否為零 -

#!/usr/bin/ruby

File.zero?( "test.txt" )      # => true

以下命令返回檔案的大小 -

#!/usr/bin/ruby

File.size?( "text.txt" )     # => 1002

以下命令可用於查詢檔案型別 -

#!/usr/bin/ruby

File::ftype( "test.txt" )     # => file

ftype 方法透過返回以下之一來識別檔案型別:file、directory、characterSpecial、blockSpecial、fifo、link、socket 或 unknown。

以下命令可用於查詢檔案建立、修改或上次訪問的時間 -

#!/usr/bin/ruby

File::ctime( "test.txt" ) # => Fri May 09 10:06:37 -0700 2008
File::mtime( "text.txt" ) # => Fri May 09 10:44:44 -0700 2008
File::atime( "text.txt" ) # => Fri May 09 10:45:01 -0700 2008

Ruby 中的目錄

所有檔案都包含在各種目錄中,Ruby 也能很好地處理這些目錄。File 類處理檔案,而目錄由 Dir 類處理。

遍歷目錄

要在 Ruby 程式中更改目錄,請使用 Dir.chdir,如下所示。此示例將當前目錄更改為 /usr/bin

Dir.chdir("/usr/bin")

您可以使用 Dir.pwd 找出當前目錄是什麼 -

puts Dir.pwd # This will return something like /usr/bin

您可以使用 Dir.entries 獲取特定目錄中檔案和目錄的列表 -

puts Dir.entries("/usr/bin").join(' ')

Dir.entries 返回一個包含指定目錄中所有條目的陣列。Dir.foreach 提供相同的功能 -

Dir.foreach("/usr/bin") do |entry|
   puts entry
end

獲取目錄列表的更簡潔方法是使用 Dir 的類陣列方法 -

Dir["/usr/bin/*"]

建立目錄

Dir.mkdir 可用於建立目錄 -

Dir.mkdir("mynewdir")

您還可以使用 mkdir 為新目錄(而非已存在的目錄)設定許可權 -

注意 - 掩碼 755 將所有者、組、世界[任何人]的許可權設定為 rwxr-xr-x,其中 r = 讀取、w = 寫入,x = 執行。

Dir.mkdir( "mynewdir", 755 )

刪除目錄

Dir.delete 可用於刪除目錄。Dir.unlinkDir.rmdir 執行完全相同的功能,併為了方便而提供。

Dir.delete("testdir")

建立檔案和臨時目錄

臨時檔案是在程式執行期間可能短暫建立的檔案,但不是永久的資訊儲存。

Dir.tmpdir 提供當前系統上臨時目錄的路徑,儘管預設情況下該方法不可用。要使 Dir.tmpdir 可用,需要使用 require 'tmpdir'。

您可以將 Dir.tmpdirFile.join 結合使用以建立與平臺無關的臨時檔案 -

require 'tmpdir'
   tempfilename = File.join(Dir.tmpdir, "tingtong")
   tempfile = File.new(tempfilename, "w")
   tempfile.puts "This is a temporary file"
   tempfile.close
   File.delete(tempfilename)

此程式碼建立了一個臨時檔案,向其中寫入資料,然後將其刪除。Ruby 的標準庫還包含一個名為 Tempfile 的庫,可以為您建立臨時檔案 -

require 'tempfile'
   f = Tempfile.new('tingtong')
   f.puts "Hello"
   puts f.path
   f.close

內建函式

以下是處理檔案和目錄的 Ruby 內建函式 -

Ruby - 異常

執行和異常總是同時出現。如果您開啟一個不存在的檔案,那麼如果您沒有正確處理這種情況,那麼您的程式被認為質量不高。

如果發生異常,程式將停止。因此,異常用於處理程式執行期間可能發生的各種型別的錯誤,並採取適當的措施,而不是完全停止程式。

Ruby 提供了一個很好的機制來處理異常。我們將可能引發異常的程式碼包含在 begin/end 程式碼塊中,並使用 rescue 子句告訴 Ruby 我們想要處理的異常型別。

語法

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
else  
# Other exceptions
ensure
# Always will be executed
end

beginrescue 的所有內容都受到保護。如果在此程式碼塊執行期間發生異常,則控制權將傳遞到 rescueend 之間的程式碼塊。

對於 begin 程式碼塊中的每個 rescue 子句,Ruby 依次將引發的異常與每個引數進行比較。如果 rescue 子句中命名的異常與當前丟擲的異常的型別相同,或者是的超類,則匹配將成功。

如果異常與指定的任何錯誤型別都不匹配,則允許在所有 rescue 子句之後使用 else 子句。

示例

即時演示
#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
      file = STDIN
end
print file, "==", STDIN, "\n"

這將產生以下結果。您可以看到 STDIN 被替換為 file,因為 open 失敗了。

#<IO:0xb7d16f84>==#<IO:0xb7d16f84>

使用 retry 語句

您可以使用 rescue 程式碼塊捕獲異常,然後使用 retry 語句從頭開始執行 begin 程式碼塊。

語法

begin
   # Exceptions raised by this code will 
   # be caught by the following rescue clause
rescue
   # This block will capture all types of exceptions
   retry  # This will move control to the beginning of begin
end

示例

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
   fname = "existant_file"
   retry
end

以下是流程 -

  • 在 open 處發生異常。
  • 進入 rescue。fname 已重新分配。
  • 透過 retry 返回到 begin 的開頭。
  • 這次檔案成功開啟。
  • 繼續執行必要的過程。

注意 - 請注意,如果重新替換名稱的檔案不存在,此示例程式碼將無限期重試。如果您將 retry 用於異常處理,請小心。

使用 raise 語句

您可以使用 raise 語句引發異常。以下方法在每次呼叫時都會引發異常。將列印其第二個訊息。

語法

raise 

OR

raise "Error Message" 

OR

raise ExceptionType, "Error Message"

OR

raise ExceptionType, "Error Message" condition

第一種形式只是重新引發當前異常(如果當前沒有異常,則引發 RuntimeError)。這用於需要在傳遞異常之前攔截異常的異常處理程式。

第二種形式建立一個新的 RuntimeError 異常,將其訊息設定為給定的字串。然後,此異常將向上拋到呼叫堆疊。

第三種形式使用第一個引數建立異常,然後將關聯的訊息設定為第二個引數。

第四種形式類似於第三種形式,但您可以新增任何條件語句(如 unless)來引發異常。

示例

即時演示
#!/usr/bin/ruby

begin  
   puts 'I am before the raise.'  
   raise 'An error has occurred.'  
   puts 'I am after the raise.'  
rescue  
   puts 'I am rescued.'  
end  
puts 'I am after the begin block.'  

這將產生以下結果:

I am before the raise.  
I am rescued.  
I am after the begin block.  

另一個顯示 raise 用法的示例 -

即時演示
#!/usr/bin/ruby

begin  
   raise 'A test exception.'  
rescue Exception => e  
   puts e.message  
   puts e.backtrace.inspect  
end  

這將產生以下結果:

A test exception.
["main.rb:4"]

使用 ensure 語句

有時,您需要保證在程式碼塊結束時執行某些處理,無論是否引發了異常。例如,您可能在進入程式碼塊時打開了檔案,並且需要確保在程式碼塊退出時關閉檔案。

ensure 子句就是這樣做的。ensure 在最後一個 rescue 子句之後,幷包含一個始終會在程式碼塊終止時執行的程式碼塊。無論程式碼塊是否正常退出、是否引發並捕獲異常或是否被未捕獲的異常終止,ensure 程式碼塊都將執行。

語法

begin 
   #.. process 
   #..raise exception
rescue 
   #.. handle error 
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

示例

即時演示
begin
   raise 'A test exception.'
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
ensure
   puts "Ensuring execution"
end

這將產生以下結果:

A test exception.
["main.rb:4"]
Ensuring execution

使用 else 語句

如果存在 else 子句,它將在 rescue 子句之後以及任何 ensure 之前。

只有在程式碼主體沒有引發異常時才會執行 else 子句的主體。

語法

begin 
   #.. process 
   #..raise exception
rescue 
   # .. handle error
else
   #.. executes if there is no exception
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

示例

即時演示
begin
   # raise 'A test exception.'
   puts "I'm not raising exception"
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
else
   puts "Congratulations-- no errors!"
ensure
   puts "Ensuring execution"
end

這將產生以下結果:

I'm not raising exception
Congratulations-- no errors!
Ensuring execution

可以使用 $! 變數捕獲引發的錯誤訊息。

捕獲和丟擲

雖然 raise 和 rescue 的異常機制非常適合在出現問題時放棄執行,但在正常處理過程中能夠跳出某些深度巢狀的結構有時也很不錯。這就是 catch 和 throw 發揮作用的地方。

catch 定義一個用給定名稱(可以是 Symbol 或 String)標記的程式碼塊。程式碼塊正常執行,直到遇到 throw。

語法

throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end

OR

throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end

示例

以下示例使用 throw 在對任何提示做出響應時鍵入“!”以終止與使用者的互動。

def promptAndGet(prompt)
   print prompt
   res = readline.chomp
   throw :quitRequested if res == "!"
   return res
end

catch :quitRequested do
   name = promptAndGet("Name: ")
   age = promptAndGet("Age: ")
   sex = promptAndGet("Sex: ")
   # ..
   # process information
end
promptAndGet("Name:")

您應該在您的機器上嘗試以上程式,因為它需要手動互動。這將產生以下結果 -

Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby

Exception 類

Ruby 的標準類和模組會引發異常。所有異常類都形成一個層次結構,Exception 類位於頂部。下一層包含七種不同的型別 -

  • Interrupt
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

此級別還有另一個異常 Fatal,但 Ruby 直譯器僅在內部使用它。

ScriptError 和 StandardError 都有許多子類,但我們這裡無需詳細介紹。重要的是,如果我們建立自己的異常類,則它們需要是 Exception 類或其後代之一的子類。

讓我們看一個例子 -

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      @reason = reason
   end
end

現在,看一下以下示例,它將使用此異常 -

File.open(path, "w") do |file|
begin
   # Write out the data ...
rescue
   # Something went wrong!
   raise FileSaveError.new($!)
end
end

這裡的重要行是 raise FileSaveError.new($!)。我們呼叫 raise 以發出已發生異常的訊號,並將 FileSaveError 的新例項傳遞給它,原因是導致資料寫入失敗的特定異常。

Ruby - 面向物件

Ruby 是一種純面向物件的語言,在 Ruby 中,一切皆物件。Ruby 中的每個值都是物件,即使是最原始的值:字串、數字,甚至 true 和 false。甚至類本身也是一個物件,它是 Class 類的例項。本章將帶您瞭解與面向物件 Ruby 相關的所有主要功能。

類用於指定物件的形態,它將資料表示和操作該資料的方法組合到一個簡潔的包中。類中的資料和方法稱為類的成員。

Ruby 類定義

定義類時,您定義了資料型別的藍圖。這實際上並沒有定義任何資料,但它確實定義了類名的含義,即類的物件將包含什麼以及可以在此類物件上執行哪些操作。

類定義以關鍵字 class 後跟類名開頭,並以end分隔。例如,我們使用關鍵字 class 定義了 Box 類,如下所示:

class Box
   code
end

名稱必須以大寫字母開頭,按照慣例,包含多個單詞的名稱會將每個單詞的首字母大寫並連線在一起,沒有分隔字元(駝峰命名法)。

定義 Ruby 物件

類提供了物件的藍圖,因此基本上物件是從類建立的。我們使用new關鍵字宣告類的物件。以下語句聲明瞭 Box 類的兩個物件:

box1 = Box.new
box2 = Box.new

initialize 方法

initialize 方法是標準的 Ruby 類方法,其工作方式與其他面向物件程式語言中的建構函式幾乎相同。當您希望在建立物件時初始化一些類變數時,initialize 方法很有用。此方法可以接受引數列表,並且像任何其他 ruby 方法一樣,它將以def關鍵字開頭,如下所示:

class Box
   def initialize(w,h)
      @width, @height = w, h
   end
end

例項變數

例項變數是一種類屬性,一旦使用類建立了物件,它們就成為物件的屬性。每個物件的屬性都是單獨分配的,並且與其他物件不共享任何值。在類中使用 @ 運算子訪問它們,但要在類外部訪問它們,我們使用public方法,稱為訪問器方法。如果我們採用上面定義的類Box,那麼 @width 和 @height 就是 Box 類的例項變數。

class Box
   def initialize(w,h)
      # assign instance variables
      @width, @height = w, h
   end
end

訪問器和設定器方法

要使變數從類外部可用,必須在訪問器方法中定義它們,這些訪問器方法也稱為 getter 方法。以下示例顯示了訪問器方法的使用:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# create an object
box = Box.new(10, 20)

# use accessor methods
x = box.printWidth()
y = box.printHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

執行上述程式碼時,會產生以下結果:

Width of the box is : 10
Height of the box is : 20

類似於用於訪問變數值的訪問器方法,Ruby 提供了一種方法,可以透過設定器方法從類外部設定這些變數的值,設定器方法定義如下:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # setter methods
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# create an object
box = Box.new(10, 20)

# use setter methods
box.setWidth = 30
box.setHeight = 50

# use accessor methods
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

執行上述程式碼時,會產生以下結果:

Width of the box is : 30
Height of the box is : 50

例項方法

例項方法也與我們使用def關鍵字定義任何其他方法的方式相同,並且只能使用類例項來使用,如下所示。它們的功能不僅限於訪問例項變數,而且還可以根據您的需求執行更多操作。

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"

執行上述程式碼時,會產生以下結果:

Area of the box is : 200

類方法和變數

類變數是一個變數,它在類的所有例項之間共享。換句話說,該變數只有一個例項,並且可以透過物件例項訪問它。類變數以兩個 @ 字元 (@@) 為字首。類變數必須在類定義中初始化,如下所示。

類方法使用def self.methodname()定義,以 end 分隔符結尾,並將使用類名作為classname.methodname呼叫,如以下示例所示:

#!/usr/bin/ruby -w

class Box
   # Initialize our class variables
   @@count = 0
   def initialize(w,h)
      # assign instance avriables
      @width, @height = w, h

      @@count += 1
   end

   def self.printCount()
      puts "Box count is : #@@count"
   end
end

# create two object
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)

# call class method to print box count
Box.printCount()

執行上述程式碼時,會產生以下結果:

Box count is : 2

to_s 方法

您定義的任何類都應該有一個to_s例項方法來返回物件的字串表示形式。以下是一個簡單的示例,用於根據寬度和高度表示 Box 物件:

即時演示
#!/usr/bin/ruby -w

class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # define to_s method
   def to_s
      "(w:#@width,h:#@height)"  # string formatting of the object.
   end
end

# create an object
box = Box.new(10, 20)

# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"

執行上述程式碼時,會產生以下結果:

String representation of box is : (w:10,h:20)

訪問控制

Ruby 在例項方法級別為您提供了三種級別的保護,可以是public、private 或 protected。Ruby 不會對例項變數和類變數應用任何訪問控制。

  • 公共方法 - 公共方法可以被任何人呼叫。方法預設情況下是公共的,初始化方法除外,初始化方法始終是私有的。

  • 私有方法 - 無法從類外部訪問或檢視私有方法。只有類方法可以訪問私有成員。

  • 受保護的方法 - 受保護的方法只能由定義類及其子類的物件呼叫。訪問許可權保持在家族內部。

以下是一個簡單的示例,用於顯示所有三個訪問修飾符的語法:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method by default it is public
   def getArea
      getWidth() * getHeight
   end

   # define private accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # instance method to print area
   def printArea
      @area = getWidth() * getHeight
      puts "Big box area is : #@area"
   end
   # make it protected
   protected :printArea
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"

# try to call protected or methods
box.printArea()

執行上述程式碼時,會產生以下結果。這裡,第一個方法成功呼叫,但第二個方法出現了問題。

Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)

類繼承

面向物件程式設計中最重要的概念之一是繼承。繼承允許我們根據另一個類來定義一個類,這使得建立和維護應用程式變得更加容易。

繼承還提供了重用程式碼功能和加快實現時間的機會,但不幸的是,Ruby 不支援多級繼承,但 Ruby 支援mixin。Mixin 就像多重繼承的一種專門實現,其中只繼承介面部分。

建立類時,程式設計師可以指定新類應該繼承現有類的成員,而不是完全編寫新的資料成員和成員函式。這個現有類稱為基類或超類,新類稱為派生類或子類

Ruby 還支援子類化概念,即繼承,以下示例解釋了該概念。擴充套件類的語法很簡單。只需在類語句中新增 < 字元和超類的名稱即可。例如,以下將BigBox類定義為Box類的子類:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# define a subclass
class BigBox < Box

   # add a new instance method
   def printArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# create an object
box = BigBox.new(10, 20)

# print the area
box.printArea()

執行上述程式碼時,會產生以下結果:

Big box area is : 200

方法重寫

雖然您可以在派生類中新增新功能,但有時您可能希望更改父類中已定義方法的行為。您可以簡單地保留相同的方法名並重寫方法的功能,如下面的示例所示:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# define a subclass
class BigBox < Box

   # change existing getArea method as follows
   def getArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# create an object
box = BigBox.new(10, 20)

# print the area using overriden method.
box.getArea()

運算子過載

我們希望 + 運算子使用 + 執行兩個 Box 物件的向量加法,* 運算子將 Box 的寬度和高度乘以一個標量,而一元 - 運算子則對 Box 的寬度和高度取反。以下是定義了數學運算子的 Box 類版本:

class Box
   def initialize(w,h)     # Initialize the width and height
      @width,@height = w, h
   end

   def +(other)       # Define + to do vector addition
      Box.new(@width + other.width, @height + other.height)
   end

   def -@           # Define unary minus to negate width and height
      Box.new(-@width, -@height)
   end

   def *(scalar)           # To perform scalar multiplication
      Box.new(@width*scalar, @height*scalar)
   end
end

凍結物件

有時,我們希望阻止物件被更改。Object 中的 freeze 方法允許我們執行此操作,有效地將物件轉換為常量。透過呼叫Object.freeze可以凍結任何物件。凍結的物件不能修改:您不能更改其例項變數。

您可以使用Object.frozen?方法檢查給定物件是否已凍結,如果物件已凍結,則該方法返回 true,否則返回 false 值。以下示例闡明瞭這個概念:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # setter methods
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# create an object
box = Box.new(10, 20)

# let us freez this object
box.freeze
if( box.frozen? )
   puts "Box object is frozen object"
else
   puts "Box object is normal object"
end

# now try using setter methods
box.setWidth = 30
box.setHeight = 50

# use accessor methods
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

執行上述程式碼時,會產生以下結果:

Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
   from test.rb:39

類常量

您可以透過將直接的數字或字串值分配給未使用 @ 或 @@ 定義的變數來定義類中的常量。按照慣例,我們將常量名稱保持為大寫。

定義常量後,您無法更改其值,但可以在類內部像變數一樣直接訪問常量,但如果要從類外部訪問常量,則必須使用classname::constant,如下面的示例所示。

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   BOX_COMPANY = "TATA Inc"
   BOXWEIGHT = 10
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"

執行上述程式碼時,會產生以下結果:

Area of the box is : 200
TATA Inc
Box weight is: 10

類常量是繼承的,並且可以像例項方法一樣被覆蓋。

使用 Allocate 建立物件

可能存在您希望在不呼叫其建構函式initialize(即不使用 new 方法)的情況下建立物件的情況,在這種情況下,您可以呼叫allocate,它將為您建立一個未初始化的物件,如以下示例所示:

即時演示
#!/usr/bin/ruby -w

# define a class
class Box
   attr_accessor :width, :height

   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method
   def getArea
      @width * @height
   end
end

# create an object using new
box1 = Box.new(10, 20)

# create another object using allocate
box2 = Box.allocate

# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"

# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"

執行上述程式碼時,會產生以下結果:

Area of the box is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in `getArea': undefined method `*' 
   for nil:NilClass (NoMethodError) from test.rb:29

類資訊

如果類定義是可執行程式碼,這意味著它們在某個物件的上下文中執行:self 必須引用某些內容。讓我們找出它是什麼。

#!/usr/bin/ruby -w

class Box
   # print class information
   puts "Type of self = #{self.type}"
   puts "Name of self = #{self.name}"
end

執行上述程式碼時,會產生以下結果:

Type of self = Class
Name of self = Box

這意味著類定義是在該類作為當前物件的情況下執行的。這意味著元類及其超類中的方法將在方法定義的執行期間可用。

Ruby - 正則表示式

正則表示式是一系列特殊的字元,它可以幫助您使用包含在模式中的專門語法匹配或查詢其他字串或字串集。

正則表示式字面量是在斜槓之間或在任意分隔符之間以及 %r 之後的模式,如下所示:

語法

/pattern/
/pattern/im    # option can be specified
%r!/usr/local! # general delimited regular expression

示例

即時演示
#!/usr/bin/ruby

line1 = "Cats are smarter than dogs";
line2 = "Dogs also like meat";

if ( line1 =~ /Cats(.*)/ )
   puts "Line1 contains Cats"
end
if ( line2 =~ /Cats(.*)/ )
   puts "Line2 contains  Dogs"
end

這將產生以下結果:

Line1 contains Cats

正則表示式修飾符

正則表示式字面量可以包含一個可選的修飾符來控制匹配的各個方面。修飾符在第二個斜槓字元之後指定,如前所述,可以用以下字元之一表示:

序號 修飾符和說明
1

i

i

2

匹配文字時忽略大小寫。

o

3

x

僅執行一次 #{} 插值,即在第一次評估正則表示式字面量時。

4

m

m

5

忽略空格並在正則表示式中允許註釋。

n

匹配多行,將換行符識別為普通字元。

# Following matches a single slash character, no escape required
%r|/|

# Flag characters are allowed with this syntax, too
%r[</(.*)>]i

u,e,s,n

除了控制字元(**(+ ? . * ^ $ ( ) [ ] { } | \)**)外,所有字元都匹配自身。您可以透過在控制字元前面加上反斜槓來轉義它。

正則表示式示例

搜尋和替換

使用正則表示式的一些最重要的 String 方法是subgsub,以及它們的原位變體sub!gsub!

所有這些方法都使用 Regexp 模式執行搜尋和替換操作。sub & sub! 替換模式的第一次出現,而gsub & gsub! 替換所有出現。

subgsub返回一個新字串,保持原始字串不變,而sub!gsub!修改其呼叫的字串。

以下是示例 -

即時演示
#!/usr/bin/ruby

phone = "2004-959-559 #This is Phone Number"

# Delete Ruby-style comments
phone = phone.sub!(/#.*$/, "")   
puts "Phone Num : #{phone}"

# Remove anything other than digits
phone = phone.gsub!(/\D/, "")    
puts "Phone Num : #{phone}"

這將產生以下結果:

Phone Num : 2004-959-559
Phone Num : 2004959559

以下是另一個示例 -

即時演示
#!/usr/bin/ruby

text = "rails are rails, really good Ruby on Rails"

# Change "rails" to "Rails" throughout
text.gsub!("rails", "Rails")

# Capitalize the word "Rails" throughout
text.gsub!(/\brails\b/, "Rails")
puts "#{text}"

這將產生以下結果:

Rails are Rails, really good Ruby on Rails

Ruby/DBI 教程

本章將教你如何使用 Ruby 訪問資料庫。Ruby DBI模組為 Ruby 指令碼提供了一個與 Perl DBI 模組類似的資料庫無關介面。

DBI 代表 Ruby 的資料庫獨立介面,這意味著 DBI 在 Ruby 程式碼和底層資料庫之間提供了一個抽象層,允許你非常輕鬆地切換資料庫實現。它定義了一組方法、變數和約定,這些方法、變數和約定提供了與資料庫一致的介面,而與使用的實際資料庫無關。

DBI 可以與以下介面互動 -

  • ADO (ActiveX 資料物件)
  • DB2
  • Frontbase
  • mSQL
  • MySQL
  • ODBC
  • Oracle
  • OCI8 (Oracle)
  • PostgreSQL
  • 代理/伺服器
  • SQLite
  • SQLRelay

DBI 應用程式的體系結構

DBI 獨立於後端可用的任何資料庫。無論你是在使用 Oracle、MySQL 還是 Informix 等,都可以使用 DBI。從下面的架構圖可以清楚地看出這一點。

Ruby DBI Architecture

Ruby DBI 的通用架構使用兩層 -

  • 資料庫介面 (DBI) 層。此層與資料庫無關,並提供了一組通用的訪問方法,無論你與之通訊的資料庫伺服器型別如何,這些方法的使用方式都相同。

  • 資料庫驅動程式 (DBD) 層。此層與資料庫相關;不同的驅動程式提供對不同資料庫引擎的訪問。MySQL 有一個驅動程式,PostgreSQL 有另一個驅動程式,InterBase 有另一個驅動程式,Oracle 有另一個驅動程式,依此類推。每個驅動程式都解釋來自 DBI 層的請求,並將它們對映到適合給定型別資料庫伺服器的請求。

先決條件

如果你想編寫 Ruby 指令碼以訪問 MySQL 資料庫,則需要安裝 Ruby MySQL 模組。

如上所述,此模組充當 DBD,可以從 https://www.tmtm.org/en/mysql/ruby/ 下載。

獲取和安裝 Ruby/DBI

你可以使用 Ruby Gems 包管理器安裝 ruby DBI

gem install dbi

在開始此安裝之前,請確保你具有 root 許可權。現在,按照以下步驟操作 -

步驟 1

$ tar zxf dbi-0.2.0.tar.gz

步驟 2

進入發行版目錄dbi-0.2.0並使用該目錄中的setup.rb指令碼對其進行配置。最通用的配置命令如下所示,在 config 引數後面沒有引數。此命令將配置發行版以預設安裝所有驅動程式。

$ ruby setup.rb config

更具體地說,提供一個 --with 選項,該選項列出要使用的發行版的特定部分。例如,要僅配置主 DBI 模組和 MySQL DBD 級驅動程式,請發出以下命令 -

$ ruby setup.rb config --with = dbi,dbd_mysql

步驟 3

最後一步是使用以下命令構建驅動程式並安裝它 -

$ ruby setup.rb setup
$ ruby setup.rb install

資料庫連線

假設我們將要使用 MySQL 資料庫,在連線到資料庫之前,請確保以下事項 -

  • 你已建立了一個數據庫 TESTDB。

  • 你已在 TESTDB 中建立了 EMPLOYEE。

  • 此表具有欄位 FIRST_NAME、LAST_NAME、AGE、SEX 和 INCOME。

  • 使用者 ID“testuser”和密碼“test123”已設定為訪問 TESTDB。

  • Ruby 模組 DBI 已正確安裝在你的機器上。

  • 你已閱讀 MySQL 教程以瞭解 MySQL 基礎知識。

以下是連線 MySQL 資料庫“TESTDB”的示例

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   # get server version string and display it
   row = dbh.select_one("SELECT VERSION()")
   puts "Server version: " + row[0]
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

在執行此指令碼時,它會在我們的 Linux 機器上產生以下結果。

Server version: 5.0.45

如果與資料來源建立了連線,則返回資料庫控制代碼並將其儲存到dbh以供進一步使用,否則dbh設定為 nil 值,e.erre::errstr分別返回錯誤程式碼和錯誤字串。

最後,在退出之前,請確保資料庫連線已關閉並釋放了資源。

INSERT 操作

當你想將記錄建立到資料庫表中時,需要使用 INSERT 操作。

一旦建立了資料庫連線,我們就可以使用do方法或prepareexecute方法在資料庫表中建立表或記錄。

使用 do 語句

可以透過呼叫**do**資料庫控制代碼方法來執行不返回行的語句。此方法接受一個語句字串引數,並返回該語句影響的行數。

dbh.do("DROP TABLE IF EXISTS EMPLOYEE")
dbh.do("CREATE TABLE EMPLOYEE (
   FIRST_NAME  CHAR(20) NOT NULL,
   LAST_NAME  CHAR(20),
   AGE INT,  
   SEX CHAR(1),
   INCOME FLOAT )" );

類似地,您可以執行SQL的INSERT語句以在EMPLOYEE表中建立記錄。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   dbh.do( "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME)
      VALUES ('Mac', 'Mohan', 20, 'M', 2000)" )
   puts "Record has been created"
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

使用prepare和execute

您可以使用DBI類的prepareexecute方法透過Ruby程式碼執行SQL語句。

記錄建立需要以下步驟:

  • 使用INSERT語句準備SQL語句。這將使用prepare方法完成。

  • 執行SQL查詢以從資料庫中選擇所有結果。這將使用execute方法完成。

  • 釋放語句控制代碼。這將使用finish API完成

  • 如果一切順利,則**commit**此操作,否則您可以**rollback**整個事務。

以下是使用這兩種方法的語法:

sth = dbh.prepare(statement)
sth.execute
   ... zero or more SQL operations ...
sth.finish

這兩種方法可以用來將**bind**值傳遞給SQL語句。可能存在需要輸入的值事先未給出的情況。在這種情況下,使用繫結值。在實際值的位置使用問號(?),然後透過execute() API傳遞實際值。

以下是在EMPLOYEE表中建立兩條記錄的示例:

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare( "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME)
      VALUES (?, ?, ?, ?, ?)" )
   sth.execute('John', 'Poul', 25, 'M', 2300)
   sth.execute('Zara', 'Ali', 17, 'F', 1000)
   sth.finish
   dbh.commit
   puts "Record has been created"
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

如果一次有多個INSERT,那麼先準備語句,然後在迴圈中多次執行它,比每次透過迴圈呼叫do更有效。

讀取操作

任何資料庫上的讀取操作都意味著從資料庫中獲取一些有用的資訊。

一旦我們的資料庫連線建立,我們就可以對該資料庫進行查詢。我們可以使用do方法或prepareexecute方法從資料庫表中獲取值。

記錄獲取需要以下步驟:

  • 根據所需條件準備SQL查詢。這將使用prepare方法完成。

  • 執行SQL查詢以從資料庫中選擇所有結果。這將使用execute方法完成。

  • 逐一獲取所有結果並列印這些結果。這將使用fetch方法完成。

  • 釋放語句控制代碼。這將使用finish方法完成。

以下是查詢EMPLOYEE表中所有工資超過1000的記錄的過程。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("SELECT * FROM EMPLOYEE WHERE INCOME > ?")
   sth.execute(1000)

   sth.fetch do |row|
   printf "First Name: %s, Last Name : %s\n", row[0], row[1]
   printf "Age: %d, Sex : %s\n", row[2], row[3]
   printf "Salary :%d \n\n", row[4]
end
   sth.finish
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

這將產生以下結果:

First Name: Mac, Last Name : Mohan
Age: 20, Sex : M
Salary :2000

First Name: John, Last Name : Poul
Age: 25, Sex : M
Salary :2300

還有更多從資料庫中獲取記錄的快捷方法。如果您感興趣,請參閱獲取結果,否則繼續下一節。

更新操作

任何資料庫上的UPDATE操作都意味著更新資料庫中已存在的一條或多條記錄。以下是更新所有SEX為'M'的記錄的過程。在這裡,我們將所有男性的AGE增加一年。這將分三個步驟進行:

  • 根據所需條件準備SQL查詢。這將使用prepare方法完成。

  • 執行SQL查詢以從資料庫中選擇所有結果。這將使用execute方法完成。

  • 釋放語句控制代碼。這將使用finish方法完成。

  • 如果一切順利,則**commit**此操作,否則您可以**rollback**整個事務。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = ?")
   sth.execute('M')
   sth.finish
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

刪除操作

當您想從資料庫中刪除一些記錄時,需要DELETE操作。以下是刪除EMPLOYEE中所有AGE大於20的記錄的過程。此操作將執行以下步驟。

  • 根據所需條件準備SQL查詢。這將使用prepare方法完成。

  • 執行SQL查詢以從資料庫中刪除所需的記錄。這將使用execute方法完成。

  • 釋放語句控制代碼。這將使用finish方法完成。

  • 如果一切順利,則**commit**此操作,否則您可以**rollback**整個事務。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("DELETE FROM EMPLOYEE WHERE AGE > ?")
   sth.execute(20)
   sth.finish
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

執行事務

事務是一種確保資料一致性的機制。事務應具有以下四個屬性:

  • 原子性 - 事務要麼完成,要麼什麼也不發生。

  • 一致性 - 事務必須從一致的狀態開始,並使系統處於一致的狀態。

  • 隔離性 - 事務的中間結果在當前事務之外不可見。

  • 永續性 - 一旦事務提交,其效果將是持久的,即使在系統故障後也是如此。

DBI提供了兩種方法來commitrollback事務。還有一個名為transaction的方法可用於實現事務。有兩種簡單的方法來實現事務:

方法一

第一種方法使用DBI的commitrollback方法顯式提交或取消事務:

dbh['AutoCommit'] = false # Set auto commit to false.
begin
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
   dbh.commit
rescue
   puts "transaction failed"
   dbh.rollback
end
dbh['AutoCommit'] = true

方法二

第二種方法使用transaction方法。這更簡單,因為它接受一個包含構成事務的語句的程式碼塊。transaction方法執行該塊,然後自動呼叫commitrollback,具體取決於該塊成功還是失敗:

dbh['AutoCommit'] = false # Set auto commit to false.
dbh.transaction do |dbh|
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
end
dbh['AutoCommit'] = true

COMMIT操作

Commit是向資料庫發出最終確認更改的訊號的操作,此操作後,任何更改都無法恢復。

以下是如何呼叫commit方法的簡單示例。

dbh.commit

ROLLBACK操作

如果您對一個或多個更改不滿意,並且希望完全恢復這些更改,則使用rollback方法。

以下是如何呼叫rollback方法的簡單示例。

dbh.rollback

斷開資料庫連線

要斷開資料庫連線,請使用disconnect API。

dbh.disconnect

如果使用者使用disconnect方法關閉了與資料庫的連線,則DBI會回滾任何未完成的事務。但是,您的應用程式最好顯式呼叫commit或rollback,而不是依賴任何DBI的實現細節。

處理錯誤

錯誤來源很多。一些示例包括執行的SQL語句中的語法錯誤、連線故障或對已取消或完成的語句控制代碼呼叫fetch方法。

如果DBI方法失敗,DBI將引發異常。DBI方法可能會引發多種型別的異常,但兩種最重要的異常類是DBI::InterfaceErrorDBI::DatabaseError

這些類的異常物件具有三個名為errerrstrstate的屬性,分別表示錯誤號、描述性錯誤字串和標準錯誤程式碼。屬性解釋如下:

  • err - 返回發生的錯誤的整數表示形式,如果DBD不支援,則返回nil。例如,Oracle DBD返回ORA-XXXX錯誤訊息的數字部分。

  • errstr - 返回發生的錯誤的字串表示形式。

  • state - 返回發生的錯誤的SQLSTATE程式碼。SQLSTATE是一個五字元長的字串。大多數DBD不支援此功能,而是返回nil。

您在上面大多數示例中都看到了以下程式碼:

rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

要獲取有關指令碼在執行過程中執行的操作的除錯資訊,您可以啟用跟蹤。為此,您必須首先載入dbi/trace模組,然後呼叫控制跟蹤模式和輸出目標的trace方法:

require "dbi/trace"
..............

trace(mode, destination)

mode值可以是0(關閉)、1、2或3,destination應該是IO物件。預設值分別為2和STDERR。

帶方法的程式碼塊

有一些方法可以建立控制代碼。這些方法可以與程式碼塊一起呼叫。將程式碼塊與方法一起使用的好處是,它們將控制代碼作為引數傳遞給程式碼塊,並在塊終止時自動清理控制代碼。以下是一些理解該概念的示例。

  • DBI.connect - 此方法生成一個數據庫控制代碼,建議在塊的末尾呼叫disconnect以斷開資料庫連線。

  • dbh.prepare - 此方法生成一個語句控制代碼,建議在塊的末尾finish。在塊中,您必須呼叫execute方法來執行語句。

  • dbh.execute - 此方法類似,除了我們不需要在塊中呼叫execute。語句控制代碼會自動執行。

示例1

DBI.connect可以接受一個程式碼塊,將資料庫控制代碼傳遞給它,並在塊的末尾自動斷開控制代碼,如下所示。

dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123") do |dbh|

示例2

dbh.prepare可以接受一個程式碼塊,將語句控制代碼傳遞給它,並在塊的末尾自動呼叫finish,如下所示。

dbh.prepare("SHOW DATABASES") do |sth|
   sth.execute
   puts "Databases: " + sth.fetch_all.join(", ")
end

示例3

dbh.execute可以接受一個程式碼塊,將語句控制代碼傳遞給它,並在塊的末尾自動呼叫finish,如下所示:

dbh.execute("SHOW DATABASES") do |sth|
   puts "Databases: " + sth.fetch_all.join(", ")
end

DBI transaction方法也接受一個程式碼塊,如上所述。

驅動程式特定函式和屬性

DBI允許資料庫驅動程式提供其他資料庫特定函式,使用者可以透過任何Handle物件的func方法呼叫這些函式。

支援驅動程式特定屬性,並且可以使用[]=[]方法設定或獲取這些屬性。

示例

#!/usr/bin/ruby

require "dbi"
begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123") 
   puts dbh.func(:client_info)
   puts dbh.func(:client_version)
   puts dbh.func(:host_info)
   puts dbh.func(:proto_info)
   puts dbh.func(:server_info)
   puts dbh.func(:thread_id)
   puts dbh.func(:stat)
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   dbh.disconnect if dbh
end

這將產生以下結果:

5.0.45
50045
Localhost via UNIX socket
10
5.0.45
150621
Uptime: 384981  Threads: 1  Questions: 1101078  Slow queries: 4 \
Opens: 324  Flush tables: 1  Open tables: 64  \
Queries per second avg: 2.860

Ruby Web應用程式 - CGI程式設計

Ruby是一種通用語言;它根本不能稱為Web語言。即使如此,Web應用程式和Web工具通常是Ruby最常見的用途。

您不僅可以用Ruby編寫自己的SMTP伺服器、FTP守護程式或Web伺服器,還可以使用Ruby執行更常見的任務,例如CGI程式設計或替換PHP。

請花幾分鐘時間閱讀CGI程式設計教程以獲取有關CGI程式設計的更多詳細資訊。

編寫CGI指令碼

最基本的Ruby CGI指令碼如下所示:

即時演示
#!/usr/bin/ruby

puts "HTTP/1.0 200 OK"
puts "Content-type: text/html\n\n"
puts "<html><body>This is a test</body></html>"

如果您將此指令碼稱為test.cgi並將其上傳到具有正確許可權的基於Unix的Web託管提供商,則可以將其用作CGI指令碼。

例如,如果您在Linux Web託管提供商處託管了網站https://www.example.com/,並且您將test.cgi上傳到主目錄並授予其執行許可權,那麼訪問https://www.example.com/test.cgi應該會返回一個HTML頁面,內容為這是一個測試

在這裡,當從Web瀏覽器請求test.cgi時,Web伺服器會在網站上查詢test.cgi,然後使用Ruby直譯器執行它。Ruby指令碼返回一個基本的HTTP標頭,然後返回一個基本的HTML文件。

使用cgi.rb

Ruby 自帶一個名為 **cgi** 的特殊庫,它能夠實現比前面 CGI 指令碼更復雜的互動。

讓我們建立一個使用 cgi 的基本 CGI 指令碼 -

即時演示
#!/usr/bin/ruby

require 'cgi'
cgi = CGI.new

puts cgi.header
puts "<html><body>This is a test</body></html>"

在這裡,您建立了一個 CGI 物件並使用它為您列印標題行。

表單處理

使用 CGI 類,您可以透過兩種方式訪問 HTML 查詢引數。假設我們給定一個 URL 為 /cgi-bin/test.cgi?FirstName = Zara&LastName = Ali。

您可以使用 CGI#[] 直接訪問引數 *FirstName* 和 *LastName*,如下所示 -

#!/usr/bin/ruby

require 'cgi'
cgi = CGI.new
cgi['FirstName'] # =>  ["Zara"]
cgi['LastName']  # =>  ["Ali"]

還有另一種訪問這些表單變數的方法。此程式碼將為您提供所有鍵值對的雜湊表 -

#!/usr/bin/ruby

require 'cgi'
cgi = CGI.new
h = cgi.params  # =>  {"FirstName"=>["Zara"],"LastName"=>["Ali"]}
h['FirstName']  # =>  ["Zara"]
h['LastName']   # =>  ["Ali"]

以下是檢索所有鍵的程式碼 -

#!/usr/bin/ruby

require 'cgi'
cgi = CGI.new
cgi.keys         # =>  ["FirstName", "LastName"]

如果表單包含多個具有相同名稱的欄位,則相應的將作為陣列返回給指令碼。[] 訪問器只返回這些值中的第一個。對 params 方法的結果進行索引以獲取所有值。

在此示例中,假設表單包含三個名為“name”的欄位,我們輸入了三個名稱“Zara”、“Huma”和“Nuha” -

#!/usr/bin/ruby

require 'cgi'
cgi = CGI.new
cgi['name']        # => "Zara"
cgi.params['name'] # => ["Zara", "Huma", "Nuha"]
cgi.keys           # => ["name"]
cgi.params         # => {"name"=>["Zara", "Huma", "Nuha"]}

**注意** - Ruby 會自動處理 GET 和 POST 方法。這兩種不同的方法沒有單獨的處理。

一個相關的基本表單,可以傳送正確的資料,其 HTML 程式碼如下 -

<html>
   <body>
      <form method = "POST" action = "http://www.example.com/test.cgi">
         First Name :<input type = "text" name = "FirstName" value = "" />
         <br />
         Last Name :<input type = "text" name = "LastName" value = "" /> 
         <input type = "submit" value = "Submit Data" />
      </form>
   </body>
</html>

建立表單和 HTML

CGI 包含大量用於建立 HTML 的方法。您會發現每個標籤對應一個方法。為了啟用這些方法,您必須透過呼叫 CGI.new 建立一個 CGI 物件。

為了使標籤巢狀更容易,這些方法將內容作為程式碼塊。程式碼塊應返回一個 *String*,該字串將用作標籤的內容。例如 -

#!/usr/bin/ruby

require "cgi"
cgi = CGI.new("html4")
cgi.out {
   cgi.html {
      cgi.head { "\n"+cgi.title{"This Is a Test"} } +
      cgi.body { "\n"+
         cgi.form {"\n"+
            cgi.hr +
            cgi.h1 { "A Form: " } + "\n"+
            cgi.textarea("get_text") +"\n"+
            cgi.br +
            cgi.submit
         }
      }
   }
}

**注意** - CGI 類的 *form* 方法可以接受一個 method 引數,該引數將設定在表單提交時使用的 HTTP 方法(GET、POST 等)。在此示例中使用的預設值為 POST。

這將產生以下結果:

Content-Type: text/html
Content-Length: 302

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Final//EN">

<HTML>
   <HEAD>
      <TITLE>This Is a Test</TITLE>
   </HEAD>
   <BODY>
      <FORM METHOD = "post" ENCTYPE = "application/x-www-form-urlencoded">
         <HR>
         <H1>A Form: </H1>
         <TEXTAREA COLS = "70" NAME = "get_text" ROWS = "10"></TEXTAREA>
         <BR>
         <INPUT TYPE = "submit">
      </FORM>
   </BODY>
</HTML>

引用字串

處理 URL 和 HTML 程式碼時,必須小心地引用某些字元。例如,斜槓字元 (/) 在 URL 中具有特殊含義,因此如果它不是路徑名的一部分,則必須對其進行 **轉義**。

例如,URL 查詢部分中的任何 / 將被轉換為字串 %2F,並且必須將其轉換回 / 才能使用它。空格和 & 符號也是特殊字元。為了處理這個問題,CGI 提供了 **CGI.escape** 和 **CGI.unescape** 兩個例程。

#!/usr/bin/ruby

require 'cgi'
puts CGI.escape(Zara Ali/A Sweet & Sour Girl")

這將產生以下結果:

Zara+Ali%2FA Sweet+%26+Sour+Girl")

#!/usr/bin/ruby

require 'cgi'
puts CGI.escapeHTML('<h1>Zara Ali/A Sweet & Sour Girl</h1>')

這將產生以下結果:

&lt;h1&gt;Zara Ali/A Sweet & Sour Girl&lt;/h1&gt;'

CGI 類中的常用方法

以下是與 CGI 類相關的方法列表 -

  • The Ruby CGI - 與標準 CGI 庫相關的方法。

Cookie 和會話

我們在不同的部分解釋了這兩個概念。請參考以下部分 -

Web 託管伺服器

您可以在網際網路上檢視以下主題,以瞭解如何在基於 Unix 的伺服器上託管您的網站 -

使用 Ruby 傳送電子郵件 - SMTP

簡單郵件傳輸協議 (SMTP) 是一種協議,它處理傳送電子郵件和在郵件伺服器之間路由電子郵件。

Ruby 提供 Net::SMTP 類用於簡單郵件傳輸協議 (SMTP) 客戶端連線,並提供兩個類方法 *new* 和 *start*。

  • **new** 接受兩個引數 -

    • 伺服器名稱,預設為 localhost。

    • 埠號,預設為眾所周知的埠 25。

  • **start** 方法接受以下引數 -

    • 伺服器 - SMTP 伺服器的 IP 名稱,預設為 localhost。

    • 埠 - 埠號,預設為 25。

    • 域名 - 郵件傳送者的域名,預設為 ENV["HOSTNAME"]。

    • 帳戶 - 使用者名稱,預設為 nil。

    • 密碼 - 使用者密碼,預設為 nil。

    • authtype - 授權型別,預設為 *cram_md5*。

SMTP 物件有一個名為 sendmail 的例項方法,通常用於執行傳送郵件的工作。它接受三個引數 -

  • 源 - 字串或陣列或任何具有 *each* 迭代器並一次返回一個字串的物件。

  • 傳送者 - 將出現在電子郵件 *from* 欄位中的字串。

  • 收件人 - 字串或字串陣列,表示收件人的地址。

示例

以下是如何使用 Ruby 指令碼傳送一封簡單電子郵件的方法。試一試 -

require 'net/smtp'

message = <<MESSAGE_END
From: Private Person <me@fromdomain.com>
To: A Test User <test@todomain.com>
Subject: SMTP e-mail test

This is a test e-mail message.
MESSAGE_END

Net::SMTP.start('localhost') do |smtp|
  smtp.send_message message, 'me@fromdomain.com', 'test@todomain.com'
end

在這裡,您將基本電子郵件放在 message 中,使用文件,注意正確格式化標頭。電子郵件需要 **From**、**To** 和 **Subject** 標頭,並用空行與電子郵件正文隔開。

要傳送郵件,您可以使用 Net::SMTP 連線到本地機器上的 SMTP 伺服器,然後使用 send_message 方法以及郵件、發件人地址和目標地址作為引數(即使發件人和收件人地址在電子郵件本身中,這些並不總是用於路由郵件)。

如果您在機器上沒有執行 SMTP 伺服器,則可以使用 Net::SMTP 與遠端 SMTP 伺服器通訊。除非您使用的是 Web 郵件服務(例如 Hotmail 或 Yahoo! Mail),否則您的電子郵件提供商將為您提供傳出郵件伺服器詳細資訊,您可以將其提供給 Net::SMTP,如下所示 -

Net::SMTP.start('mail.your-domain.com')

此程式碼行連線到 mail.your-domain.com 埠 25 上的 SMTP 伺服器,不使用任何使用者名稱或密碼。但是,如果您需要,可以指定埠號和其他詳細資訊。例如 -

Net::SMTP.start('mail.your-domain.com', 
                25, 
                'localhost', 
                'username', 'password' :plain)

此示例連線到 mail.your-domain.com 上的 SMTP 伺服器,使用明文格式的使用者名稱和密碼。它將客戶端的主機名標識為 localhost。

使用 Ruby 傳送 HTML 電子郵件

當您使用 Ruby 傳送文字訊息時,所有內容都將被視為簡單文字。即使您在文字訊息中包含 HTML 標籤,它也將顯示為簡單文字,並且 HTML 標籤不會根據 HTML 語法進行格式化。但是 Ruby Net::SMTP 提供了將 HTML 訊息作為實際 HTML 訊息傳送的選項。

傳送電子郵件訊息時,您可以指定 Mime 版本、內容型別和字元集以傳送 HTML 電子郵件。

示例

以下是傳送 HTML 內容作為電子郵件的示例。試一試 -

require 'net/smtp'

message = <<MESSAGE_END
From: Private Person <me@fromdomain.com>
To: A Test User <test@todomain.com>
MIME-Version: 1.0
Content-type: text/html
Subject: SMTP e-mail test

This is an e-mail message to be sent in HTML format

<b>This is HTML message.</b>
<h1>This is headline.</h1>
MESSAGE_END

Net::SMTP.start('localhost') do |smtp|
   smtp.send_message message, 'me@fromdomain.com', 'test@todomain.com'
end

將附件作為電子郵件傳送

要傳送包含混合內容的電子郵件,需要將 **Content-type** 標頭設定為 **multipart/mixed**。然後可以在 **邊界** 內指定文字和附件部分。

邊界以兩個連字元後跟一個唯一數字開頭,該數字不能出現在電子郵件的訊息部分中。表示電子郵件最終部分的最終邊界也必須以兩個連字元結尾。

附加檔案應使用 **pack("m")** 函式進行編碼,以便在傳輸前進行 base64 編碼。

示例

以下示例將檔案 ** /tmp/test.txt** 作為附件傳送。

require 'net/smtp'

filename = "/tmp/test.txt"
# Read a file and encode it into base64 format
filecontent = File.read(filename)
encodedcontent = [filecontent].pack("m")   # base64

marker = "AUNIQUEMARKER"
body = <<EOF
This is a test email to send an attachement.
EOF

# Define the main headers.
part1 = <<EOF
From: Private Person <me@fromdomain.net>
To: A Test User <test@todmain.com>
Subject: Sending Attachement
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary = #{marker}
--#{marker}
EOF

# Define the message action
part2 = <<EOF
Content-Type: text/plain
Content-Transfer-Encoding:8bit

#{body}
--#{marker}
EOF

# Define the attachment section
part3 = <<EOF
Content-Type: multipart/mixed; name = \"#{filename}\"
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename = "#{filename}"

#{encodedcontent}
--#{marker}--
EOF

mailtext = part1 + part2 + part3

# Let's put our code in safe area
begin 
   Net::SMTP.start('localhost') do |smtp|
      smtp.sendmail(mailtext, 'me@fromdomain.net', ['test@todmain.com'])
   end
rescue Exception => e  
   print "Exception occured: " + e  
end  

**注意** - 您可以在陣列中指定多個目標,但它們應以逗號分隔。

Ruby - 套接字程式設計

Ruby 提供了兩個級別的網路服務訪問。在低級別,您可以訪問底層作業系統中的基本套接字支援,這允許您為面向連線和無連線協議實現客戶端和伺服器。

Ruby 還有一些庫提供對特定應用程式級網路協議(如 FTP、HTTP 等)的更高級別的訪問。

本章使您瞭解網路中最著名的概念 - 套接字程式設計。

什麼是套接字?

套接字是雙向通訊通道的端點。套接字可以在一個程序內、同一臺機器上的不同程序之間或不同大陸上的不同程序之間通訊。

套接字可以在許多不同的通道型別上實現:Unix 域套接字、TCP、UDP 等。*套接字* 為處理常用傳輸提供了特定的類,以及用於處理其餘傳輸的通用介面。

套接字有自己的詞彙表 -

序號 術語 & 描述
1

將用作傳輸機制的協議族。這些值是常量,例如 PF_INET、PF_UNIX、PF_X25 等。

2

型別

兩個端點之間的通訊型別,通常對於面向連線的協議為 SOCK_STREAM,對於無連線的協議為 SOCK_DGRAM。

3

協議

通常為零,這可用於識別域和型別內協議的變體。

4

主機名

網路介面的識別符號 -

字串,可以是主機名、點分四段式地址或冒號(可能還有點)表示法的 IPv6 地址

字串“<broadcast>”指定 INADDR_BROADCAST 地址。

零長度字串,指定 INADDR_ANY,或

整數,解釋為主機位元組序中的二進位制地址。

5

每個伺服器偵聽一個或多個埠上的客戶端呼叫。埠可以是 Fixnum 埠號、包含埠號的字串或服務的名稱。

一個簡單的客戶端

在這裡,我們將編寫一個非常簡單的客戶端程式,它將開啟到給定埠和給定主機的連線。Ruby 類 **TCPSocket** 提供 *open* 函式來開啟這樣的套接字。

**TCPSocket.open(hosname, port )** 在 *port* 上開啟到 *hostname* 的 TCP 連線。

開啟套接字後,您可以像處理任何 IO 物件一樣從中讀取資料。完成後,請記住關閉它,就像關閉檔案一樣。

以下程式碼是一個非常簡單的客戶端,它連線到給定的主機和埠,從套接字讀取所有可用資料,然後退出 -

require 'socket'        # Sockets are in standard library

hostname = 'localhost'
port = 2000

s = TCPSocket.open(hostname, port)

while line = s.gets     # Read lines from the socket
   puts line.chop       # And print with platform line terminator
end
s.close                 # Close the socket when done

一個簡單的伺服器

要編寫 Internet 伺服器,我們使用 **TCPServer** 類。TCPServer 物件是 TCPSocket 物件的工廠。

現在呼叫 **TCPServer.open(hostname, port** 函式為您的服務指定一個 *port* 並建立一個 **TCPServer** 物件。

接下來,呼叫返回的 TCPServer 物件的 accept 方法。此方法等待客戶端連線到您指定的埠,然後返回一個表示與該客戶端連線的 TCPSocket 物件。

require 'socket'                 # Get sockets from stdlib

server = TCPServer.open(2000)    # Socket to listen on port 2000
loop {                           # Servers run forever
   client = server.accept        # Wait for a client to connect
   client.puts(Time.now.ctime)   # Send the time to the client
   client.puts "Closing the connection. Bye!"
   client.close                  # Disconnect from the client
}

現在,在後臺執行此伺服器,然後執行上述客戶端以檢視結果。

多客戶端 TCP 伺服器

網際網路上的大多數伺服器都設計用於同時處理大量客戶端。

Ruby 的 Thread 類使建立多執行緒伺服器變得容易。一個伺服器接受請求並立即建立一個新的執行執行緒來處理連線,同時允許主程式等待更多連線 -

require 'socket'                 # Get sockets from stdlib

server = TCPServer.open(2000)    # Socket to listen on port 2000
loop {                           # Servers run forever
   Thread.start(server.accept) do |client|
   client.puts(Time.now.ctime)   # Send the time to the client
   client.puts "Closing the connection. Bye!"
   client.close                  # Disconnect from the client
   end
}

在此示例中,您有一個永久迴圈,當 server.accept 響應時,會立即建立一個新的執行緒並啟動它以處理剛剛接受的連線,使用傳遞到執行緒的連線物件。但是,主程式會立即迴圈返回並等待新的連線。

以這種方式使用 Ruby 執行緒意味著程式碼是可移植的,並且可以在 Linux、OS X 和 Windows 上以相同的方式執行。

一個小型 Web 瀏覽器

我們可以使用套接字型檔來實現任何網際網路協議。例如,以下是一段獲取網頁內容的程式碼 -

require 'socket'
 
host = 'www.tutorialspoint.com'     # The web server
port = 80                           # Default HTTP port
path = "/index.htm"                 # The file we want 

# This is the HTTP request we send to fetch a file
request = "GET #{path} HTTP/1.0\r\n\r\n"

socket = TCPSocket.open(host,port)  # Connect to server
socket.print(request)               # Send request
response = socket.read              # Read complete response
# Split response at first blank line into headers and body
headers,body = response.split("\r\n\r\n", 2) 
print body                          # And display it

要實現類似的 Web 客戶端,您可以使用預構建的庫,如 Net::HTTP,用於處理 HTTP。以下程式碼等效於前面的程式碼 -

require 'net/http'                  # The library we need
host = 'www.tutorialspoint.com'     # The web server
path = '/index.htm'                 # The file we want 

http = Net::HTTP.new(host)          # Create a connection
headers, body = http.get(path)      # Request the file
if headers.code == "200"            # Check the status code   
   print body                        
else                                
   puts "#{headers.code} #{headers.message}" 
end

請檢查類似的庫以處理 FTP、SMTP、POP 和 IMAP 協議。

進一步閱讀

我們為您提供了套接字程式設計的快速入門。這是一個很大的主題,因此建議您閱讀 Ruby 套接字型檔和類方法 以瞭解更多詳細資訊。

Ruby - XML、XSLT 和 XPath 教程

什麼是 XML?

可擴充套件標記語言 (XML) 是一種標記語言,類似於 HTML 或 SGML。這是全球資訊網聯盟推薦的,並作為開放標準提供。

XML 是一種可移植的開源語言,允許程式設計師開發可以被其他應用程式讀取的應用程式,而不管作業系統和/或開發語言如何。

XML 在無需基於 SQL 的後端的情況下跟蹤少量到中等數量的資料方面非常有用。

XML 解析器架構和 API

XML 解析器有兩種不同的型別 -

  • SAX 式(流介面) - 在這裡,您為感興趣的事件註冊回撥,然後讓解析器遍歷文件。當您的文件很大或您有記憶體限制時,這很有用,它在從磁碟讀取檔案時解析檔案,並且整個檔案永遠不會儲存在記憶體中。

  • DOM 式(物件樹介面) - 這是全球資訊網聯盟的建議,其中整個檔案被讀入記憶體並存儲在分層(基於樹)的形式中,以表示 XML 文件的所有功能。

在處理大型檔案時,SAX 的處理速度顯然不如 DOM 快。另一方面,僅使用 DOM 可能會嚴重消耗您的資源,尤其是在處理大量小檔案時。

SAX 是隻讀的,而 DOM 允許更改 XML 檔案。由於這兩個不同的 API 實際上是互補的,因此您沒有理由不能將它們都用於大型專案。

使用 Ruby 解析和建立 XML

操作 XML 最常見的方法是使用 Sean Russell 的 REXML 庫。自 2002 年以來,REXML 一直是標準 Ruby 發行版的一部分。

REXML 是一個純 Ruby XML 處理器,符合 XML 1.0 標準。它是一個非驗證處理器,通過了所有 OASIS 非驗證一致性測試。

與其他可用的解析器相比,REXML 解析器具有以下優點 -

  • 它完全用 Ruby 編寫。
  • 它可用於 SAX 和 DOM 解析。
  • 它很輕量級,程式碼少於 2000 行。
  • 方法和類非常易於理解。
  • 基於 SAX2 的 API 和完整的 XPath 支援。
  • 隨 Ruby 安裝一起提供,無需單獨安裝。

對於我們所有的 XML 程式碼示例,讓我們使用一個簡單的 XML 檔案作為輸入 -

<collection shelf = "New Arrivals">
   <movie title = "Enemy Behind">
      <type>War, Thriller</type>
      <format>DVD</format>
      <year>2003</year>
      <rating>PG</rating>
      <stars>10</stars>
      <description>Talk about a US-Japan war</description>
   </movie>
   <movie title = "Transformers">
      <type>Anime, Science Fiction</type>
      <format>DVD</format>
      <year>1989</year>
      <rating>R</rating>
      <stars>8</stars>
      <description>A schientific fiction</description>
   </movie>
   <movie title = "Trigun">
      <type>Anime, Action</type>
      <format>DVD</format>
      <episodes>4</episodes>
      <rating>PG</rating>
      <stars>10</stars>
      <description>Vash the Stampede!</description>
   </movie>
   <movie title = "Ishtar">
      <type>Comedy</type>
      <format>VHS</format>
      <rating>PG</rating>
      <stars>2</stars>
      <description>Viewable boredom</description>
   </movie>
</collection>

DOM 式解析

讓我們首先以樹狀方式解析我們的 XML 資料。我們首先需要 rexml/document 庫;通常我們會執行 include REXML 以方便匯入到頂層名稱空間中。

#!/usr/bin/ruby -w

require 'rexml/document'
include REXML

xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)

# Now get the root element
root = xmldoc.root
puts "Root element : " + root.attributes["shelf"]

# This will output all the movie titles.
xmldoc.elements.each("collection/movie"){ 
   |e| puts "Movie Title : " + e.attributes["title"] 
}

# This will output all the movie types.
xmldoc.elements.each("collection/movie/type") {
   |e| puts "Movie Type : " + e.text 
}

# This will output all the movie description.
xmldoc.elements.each("collection/movie/description") {
   |e| puts "Movie Description : " + e.text 
}

這將產生以下結果:

Root element : New Arrivals
Movie Title : Enemy Behind
Movie Title : Transformers
Movie Title : Trigun
Movie Title : Ishtar
Movie Type : War, Thriller
Movie Type : Anime, Science Fiction
Movie Type : Anime, Action
Movie Type : Comedy
Movie Description : Talk about a US-Japan war
Movie Description : A schientific fiction
Movie Description : Vash the Stampede!
Movie Description : Viewable boredom

SAX 式解析

要以面向流的方式處理相同的資料(movies.xml 檔案),我們將定義一個偵聽器類,其方法將成為解析器回撥的目標。

注意 - 不建議對小檔案使用 SAX 式解析,這隻用於演示示例。

#!/usr/bin/ruby -w

require 'rexml/document'
require 'rexml/streamlistener'
include REXML

class MyListener
   include REXML::StreamListener
   def tag_start(*args)
      puts "tag_start: #{args.map {|x| x.inspect}.join(', ')}"
   end

   def text(data)
      return if data =~ /^\w*$/     # whitespace only
      abbrev = data[0..40] + (data.length > 40 ? "..." : "")
      puts "  text   :   #{abbrev.inspect}"
   end
end

list = MyListener.new
xmlfile = File.new("movies.xml")
Document.parse_stream(xmlfile, list)

這將產生以下結果:

tag_start: "collection", {"shelf"=>"New Arrivals"}
tag_start: "movie", {"title"=>"Enemy Behind"}
tag_start: "type", {}
   text   :   "War, Thriller"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "Talk about a US-Japan war"
tag_start: "movie", {"title"=>"Transformers"}
tag_start: "type", {}
   text   :   "Anime, Science Fiction"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "A schientific fiction"
tag_start: "movie", {"title"=>"Trigun"}
tag_start: "type", {}
   text   :   "Anime, Action"
tag_start: "format", {}
tag_start: "episodes", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "Vash the Stampede!"
tag_start: "movie", {"title"=>"Ishtar"}
tag_start: "type", {}
tag_start: "format", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "Viewable boredom"

XPath 和 Ruby

檢視 XML 的另一種方法是 XPath。這是一種偽語言,描述瞭如何在 XML 文件中定位特定元素和屬性,將該文件視為一個邏輯有序的樹。

REXML 透過 XPath 類支援 XPath。正如我們上面所看到的,它假設基於樹的解析(文件物件模型)。

#!/usr/bin/ruby -w

require 'rexml/document'
include REXML

xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)

# Info for the first movie found
movie = XPath.first(xmldoc, "//movie")
p movie

# Print out all the movie types
XPath.each(xmldoc, "//type") { |e| puts e.text }

# Get an array of all of the movie formats.
names = XPath.match(xmldoc, "//format").map {|x| x.text }
p names

這將產生以下結果:

<movie title = 'Enemy Behind'> ... </>
War, Thriller
Anime, Science Fiction
Anime, Action
Comedy
["DVD", "DVD", "DVD", "VHS"]

XSLT 和 Ruby

Ruby 可以使用兩個可用的 XSLT 解析器。這裡簡要介紹了每個解析器。

Ruby-Sablotron

此解析器由 Takahashi Masayoshi 編寫和維護。它主要為 Linux 作業系統編寫,需要以下庫 -

  • Sablot
  • Iconv
  • Expat

您可以在 Ruby-Sablotron 中找到此模組。

XSLT4R

XSLT4R 由 Michael Neumann 編寫,可以在 RAA 的庫部分(XML 下)找到。XSLT4R 使用簡單的命令列介面,儘管它也可以在第三方應用程式中使用以轉換 XML 文件。

XSLT4R 需要 XMLScan 才能執行,XMLScan 包含在 XSLT4R 存檔中,並且也是一個 100% 的 Ruby 模組。可以使用標準的 Ruby 安裝方法(即 ruby install.rb)安裝這些模組。

XSLT4R 具有以下語法 -

ruby xslt.rb stylesheet.xsl document.xml [arguments]

如果要從應用程式內部使用 XSLT4R,則可以包含 XSLT 並輸入所需的引數。以下是一個示例 -

require "xslt"

stylesheet = File.readlines("stylesheet.xsl").to_s
xml_doc = File.readlines("document.xml").to_s
arguments = { 'image_dir' => '/....' }
sheet = XSLT::Stylesheet.new( stylesheet, arguments )

# output to StdOut
sheet.apply( xml_doc )

# output to 'str'
str = ""
sheet.output = [ str ]
sheet.apply( xml_doc )

進一步閱讀

使用 Ruby 的 Web 服務 - SOAP4R

什麼是 SOAP?

簡單物件訪問協議 (SOAP) 是一種基於 XML 的跨平臺和語言無關的 RPC 協議,通常(但並非總是)使用 HTTP。

它使用 XML 編碼進行遠端過程呼叫的資訊,並使用 HTTP 透過網路在客戶端和伺服器之間傳輸這些資訊,反之亦然。

與其他技術(如 COM、CORBA 等)相比,SOAP 具有若干優勢:例如,其相對較低的部署和除錯成本、其可擴充套件性和易用性,以及針對不同語言和平臺的多個實現的存在。

請參閱我們的簡單教程 SOAP 以詳細瞭解它。

本章使您熟悉 Ruby 的 SOAP 實現 (SOAP4R)。這是一個基本的教程,因此如果您需要深入瞭解,則需要參考其他資源。

安裝 SOAP4R

SOAP4R 是 Nakamura Hiroshi 開發的 Ruby 的 SOAP 實現,可以從以下位置下載 -

注意 - 您很有可能已經安裝了此元件。

Download SOAP

如果您瞭解 gem 實用程式,則可以使用以下命令安裝 SOAP4R 和相關包。

$ gem install soap4r --include-dependencies

如果您在 Windows 上工作,則需要從上述位置下載一個壓縮檔案,並需要透過執行 ruby install.rb 使用標準安裝方法安裝它。

編寫 SOAP4R 伺服器

SOAP4R 支援兩種不同型別的伺服器 -

  • 基於 CGI/FastCGI (SOAP::RPC::CGIStub)
  • 獨立 (SOAP::RPC:StandaloneServer)

本章詳細介紹了編寫獨立伺服器。編寫 SOAP 伺服器涉及以下步驟。

步驟 1 - 繼承 SOAP::RPC::StandaloneServer 類

要實現您自己的獨立伺服器,您需要編寫一個新類,它將成為 SOAP::StandaloneServer 的子類,如下所示 -

class MyServer < SOAP::RPC::StandaloneServer
  ...............
end

注意 - 如果要編寫基於 FastCGI 的伺服器,則需要將 SOAP::RPC::CGIStub 作為父類,其餘過程將保持不變。

步驟 2 - 定義處理程式方法

第二步是編寫您希望公開給外部世界的 Web 服務方法。

它們可以寫成簡單的 Ruby 方法。例如,讓我們編寫兩個方法來新增兩個數字和除以兩個數字 -

class MyServer < SOAP::RPC::StandaloneServer
   ...............

   # Handler methods
   def add(a, b)
      return a + b
   end
   def div(a, b) 
      return a / b 
   end
end

步驟 3 - 公開處理程式方法

下一步是將我們定義的方法新增到我們的伺服器中。initialize 方法用於使用以下兩種方法之一公開服務方法 -

class MyServer < SOAP::RPC::StandaloneServer
   def initialize(*args)
      add_method(receiver, methodName, *paramArg)
   end
end

以下是引數的描述 -

序號 引數 & 說明
1

接收器

包含 methodName 方法的物件。您在與 methodDef 方法相同的類中定義服務方法,此引數為 self

2

方法名稱

由於 RPC 請求而呼叫的方法的名稱。

3

引數引數

指定(如果給出)引數名稱和引數模式。

要了解 inoutout 引數的用法,請考慮以下服務方法,該方法採用兩個引數(inParam 和 inoutParam),返回一個普通返回值 (retVal) 和另外兩個引數:inoutParamoutParam -

def aMeth(inParam, inoutParam)
   retVal = inParam + inoutParam
   outParam = inParam . inoutParam
   inoutParam = inParam * inoutParam
   return retVal, inoutParam, outParam
end

現在,我們可以公開此方法,如下所示 -

add_method(self, 'aMeth', [
   %w(in inParam),
   %w(inout inoutParam),
   %w(out outParam),
   %w(retval return)
])

步驟 4 - 啟動伺服器

最後一步是透過例項化派生類的一個例項並呼叫 start 方法來啟動伺服器。

myServer = MyServer.new('ServerName', 'urn:ruby:ServiceName', hostname, port)

myServer.start

以下是所需引數的描述 -

序號 引數 & 說明
1

伺服器名稱

伺服器名稱,您可以隨意指定。

2

urn:ruby:ServiceName

這裡 urn:ruby 是常量,但您可以為此伺服器提供唯一的 ServiceName 名稱。

3

主機名

指定此伺服器將偵聽的主機名。

4

用於 Web 服務的可用埠號。

示例

現在,使用上述步驟,讓我們編寫一個獨立伺服器:

require "soap/rpc/standaloneserver"

begin
   class MyServer < SOAP::RPC::StandaloneServer

      # Expose our services
      def initialize(*args)
         add_method(self, 'add', 'a', 'b')
         add_method(self, 'div', 'a', 'b')
      end

      # Handler methods
      def add(a, b)
         return a + b
      end
      def div(a, b) 
         return a / b 
      end
end
   server = MyServer.new("MyServer", 
            'urn:ruby:calculation', 'localhost', 8080)
   trap('INT){
      server.shutdown
   }
   server.start
rescue => err
   puts err.message
end

執行此伺服器應用程式時,它會在localhost上啟動一個獨立的 SOAP 伺服器,並在8080上監聽請求。它公開了兩種服務方法,adddiv,它們接受兩個引數並返回結果。

現在,您可以按如下方式在後臺執行此伺服器:

$ ruby MyServer.rb&

編寫 SOAP4R 客戶端

SOAP::RPC::Driver類提供對編寫 SOAP 客戶端應用程式的支援。本章描述了此類,並基於應用程式演示了其用法。

以下是呼叫 SOAP 服務所需的最少資訊:

  • SOAP 服務的 URL(SOAP 端點 URL)。
  • 服務方法的名稱空間(方法名稱空間 URI)。
  • 服務方法的名稱及其引數。

現在,我們將編寫一個 SOAP 客戶端,它將呼叫上面示例中定義的服務方法,名為adddiv

以下是建立 SOAP 客戶端的主要步驟。

步驟 1 - 建立 SOAP 驅動程式例項

我們透過呼叫其新方法建立SOAP::RPC::Driver的例項,如下所示:

SOAP::RPC::Driver.new(endPoint, nameSpace, soapAction)

以下是所需引數的描述 -

序號 引數 & 說明
1

endPoint

要連線的 SOAP 伺服器的 URL。

2

nameSpace

與此 SOAP::RPC::Driver 物件執行的所有 RPC 使用的名稱空間。

3

soapAction

HTTP 標頭的 SOAPAction 欄位的值。如果為 nil,則預設為空字串 ""。

步驟 2 - 新增服務方法

要將 SOAP 服務方法新增到SOAP::RPC::Driver,我們可以使用SOAP::RPC::Driver例項呼叫以下方法:

driver.add_method(name, *paramArg)

以下是引數的描述 -

序號 引數 & 說明
1

name

遠端 Web 服務方法的名稱。

2

引數引數

指定遠端過程的引數名稱。

步驟 3 - 呼叫 SOAP 服務

最後一步是使用SOAP::RPC::Driver例項呼叫 SOAP 服務,如下所示:

result = driver.serviceMethod(paramArg...)

這裡serviceMethod是實際的 Web 服務方法,paramArg...是傳遞給服務方法所需的引數列表。

示例

根據上述步驟,我們將編寫如下 SOAP 客戶端:

#!/usr/bin/ruby -w

require 'soap/rpc/driver'

NAMESPACE = 'urn:ruby:calculation'
URL = 'https://:8080/'

begin
   driver = SOAP::RPC::Driver.new(URL, NAMESPACE)
   
   # Add remote sevice methods
   driver.add_method('add', 'a', 'b')

   # Call remote service methods
   puts driver.add(20, 30)
rescue => err
   puts err.message
end

進一步閱讀

我向您解釋了使用 Ruby 的 Web 服務的基本概念。如果您想進一步深入瞭解,請訪問以下連結以查詢有關使用 Ruby 的 Web 服務的更多詳細資訊。

Ruby - Tk 指南

簡介

Ruby 的標準圖形使用者介面 (GUI) 是 Tk。Tk 最初是 John Ousterhout 開發的 Tcl 指令碼語言的 GUI。

Tk 具有作為唯一跨平臺 GUI 的獨特優勢。Tk 可以在 Windows、Mac 和 Linux 上執行,並在每個作業系統上提供原生外觀和感覺。

基於 Tk 的應用程式的基本元件稱為部件。元件有時也稱為視窗,因為在 Tk 中,“視窗”和“部件”通常可以互換使用。

Tk 應用程式遵循部件層次結構,其中任意數量的部件可以放置在另一個部件中,而這些部件又可以放置在另一個部件中,以此類推。Tk 程式中的主要部件稱為根部件,可以透過建立 TkRoot 類的新的例項來建立。

  • 大多數基於 Tk 的應用程式遵循相同的迴圈:建立部件、將它們放置在介面中,最後將與每個部件關聯的事件繫結到方法。

  • 有三個幾何管理器;place、gridpack負責控制介面中每個部件的大小和位置。

安裝

Ruby Tk 繫結與 Ruby 一起分發,但 Tk 是單獨安裝的。Windows 使用者可以從ActiveState 的 ActiveTcl下載一鍵式 Tk 安裝程式。

Mac 和 Linux 使用者可能不需要安裝它,因為很有可能它已經隨作業系統一起安裝了,但如果沒有,您可以下載預構建的軟體包或從Tcl 開發者交換獲取原始碼。

簡單的 Tk 應用程式

Ruby/Tk 程式的典型結構是建立主視窗或視窗(TkRoot 的例項),向其中新增部件以構建使用者介面,然後透過呼叫Tk.mainloop啟動主事件迴圈。

Ruby/Tk 的傳統Hello, World!示例如下所示:

require 'tk'

root = TkRoot.new { title "Hello, World!" }
TkLabel.new(root) do
   text 'Hello, World!'
   pack { padx 15 ; pady 15; side 'left' }
end
Tk.mainloop

這裡,在載入 tk 擴充套件模組後,我們使用TkRoot.new建立一個根級框架。然後,我們建立一個TkLabel部件作為根框架的子部件,併為標籤設定幾個選項。最後,我們打包根框架並進入主 GUI 事件迴圈。

如果您執行此指令碼,它將產生以下結果:

Ruby/Tk Hello World

Ruby/Tk 部件類

以下是各種 Ruby/Tk 類列表,可以使用它們使用 Ruby/Tk 建立所需的 GUI。

標準配置選項

所有部件都具有一些不同的配置選項,這些選項通常控制部件的顯示方式或行為方式。可用的選項當然取決於部件類。

以下是所有標準配置選項的列表,這些選項可能適用於任何 Ruby/Tk 部件。

Ruby/Tk 幾何管理

幾何管理處理根據需要定位不同小部件。Tk 中的幾何管理依賴於主小部件和從屬小部件的概念。

主小部件是一個小部件,通常是頂級視窗或框架,它將包含其他稱為從屬小部件的小部件。您可以將幾何管理器視為控制主小部件並決定將在其中顯示的內容。

幾何管理器將詢問每個從屬小部件其自然大小,或者它理想情況下希望顯示多大。然後,它獲取該資訊並將其與程式在要求幾何管理器管理該特定從屬小部件時提供的任何引數相結合。

有三個幾何管理器 *place*、*grid* 和 *pack* 負責控制介面中每個小部件的大小和位置。

  • grid 將小部件排列在網格中的幾何管理器。

  • pack 將小部件打包在空腔邊緣周圍的幾何管理器。

  • place 用於固定或橡皮膜放置的幾何管理器。

Ruby/Tk 事件處理

Ruby/Tk 支援 *事件迴圈*,它接收來自作業系統的事件。這些事件包括按鈕按下、按鍵、滑鼠移動、視窗調整大小等。

Ruby/Tk 會為您管理此事件迴圈。它將確定事件適用於哪個小部件(使用者是否單擊了此按鈕?如果按下了鍵,哪個文字框具有焦點?),並相應地分派它。各個小部件知道如何響應事件,例如,當滑鼠移到按鈕上時,按鈕可能會更改顏色,當滑鼠離開時恢復原樣。

在更高級別上,Ruby/Tk 在您的程式中呼叫回撥以指示小部件發生了某些重要事件。對於這兩種情況,您可以提供一個程式碼塊或一個 *Ruby Proc* 物件,該物件指定應用程式如何響應事件或回撥。

讓我們看看如何使用 bind 方法將基本視窗系統事件與處理它們的 Ruby 過程關聯起來。bind 的最簡單形式以字串(指示事件名稱)和程式碼塊(Tk 用於處理事件)作為輸入。

例如,要捕獲某個小部件上第一個滑鼠按鈕的 *ButtonRelease* 事件,您可以編寫:

someWidget.bind('ButtonRelease-1') {
   ....code block to handle this event...
}

事件名稱可以包含其他修飾符和詳細資訊。修飾符是一個字串,如 *Shift*、*Control* 或 *Alt*,表示按下了其中一個修飾鍵。

因此,例如,要捕獲使用者按住 *Ctrl* 鍵並單擊滑鼠右鍵時生成的事件。

someWidget.bind('Control-ButtonPress-3', proc { puts "Ouch!" })

許多 Ruby/Tk 小部件在使用者啟用它們時可以觸發 *回撥*,並且您可以使用 *command* 回撥來指定在發生這種情況時呼叫某個程式碼塊或過程。如前所述,您可以在建立小部件時指定命令回撥過程:

helpButton = TkButton.new(buttonFrame) {
   text "Help"
   command proc { showHelp }
}

或者,您可以使用小部件的 *command* 方法稍後分配它:

helpButton.command proc { showHelp }

由於 command 方法接受過程或程式碼塊,因此您也可以將前面的程式碼示例編寫為:

helpButton = TkButton.new(buttonFrame) {
   text "Help"
   command { showHelp }
}

configure 方法

configure 方法可用於設定和檢索任何小部件配置值。例如,要更改按鈕的寬度,您可以隨時呼叫 configure 方法,如下所示:

require "tk"

button = TkButton.new {
   text 'Hello World!'
   pack
}
button.configure('activebackground', 'blue')
Tk.mainloop

要獲取當前小部件的值,只需在不提供值的情況下提供它,如下所示:

color = button.configure('activebackground')

您還可以完全不帶任何選項呼叫 configure,這將為您提供所有選項及其值的列表。

cget 方法

對於簡單地檢索選項的值,configure 返回的資訊通常比您想要的更多。cget 方法僅返回當前值。

color = button.cget('activebackground')

Ruby - LDAP 教程

Ruby/LDAP 是 Ruby 的擴充套件庫。它提供了一些 LDAP 庫(如 OpenLDAP、UMich LDAP、Netscape SDK、ActiveDirectory)的介面。

應用程式開發的通用 API 在 RFC1823 中進行了描述,並且 Ruby/LDAP 支援它。

Ruby/LDAP 安裝

您可以從 SOURCEFORGE.NET 下載並安裝完整的 Ruby/LDAP 包。

在安裝 Ruby/LDAP 之前,請確保您具有以下元件:

  • Ruby 1.8.x(如果您想使用 ldap/control,至少為 1.8.2)。
  • OpenLDAP、Netscape SDK、Windows 2003 或 Windows XP。

現在,您可以使用標準的 Ruby 安裝方法。在開始之前,如果您想檢視 extconf.rb 的可用選項,請使用 '--help' 選項執行它。

$ ruby extconf.rb [--with-openldap1|--with-openldap2| \
                   --with-netscape|--with-wldap32]
$ make
$ make install

注意 - 如果您在 Windows 上構建軟體,您可能需要使用 *nmake* 而不是 *make*。

建立 LDAP 連線

這是一個兩步過程:

步驟 1 - 建立連線物件

以下是建立與 LDAP 目錄的連線的語法。

LDAP::Conn.new(host = 'localhost', port = LDAP_PORT)
  • host - 這是執行 LDAP 目錄的主機 ID。我們將將其作為 *localhost*。

  • port - 這是用於 LDAP 服務的埠。標準 LDAP 埠為 636 和 389。確保您的伺服器上使用了哪個埠,否則您可以使用 LDAP::LDAP_PORT。

此呼叫返回一個新的 *LDAP::Conn* 連線到伺服器 *host*,埠為 *port*。

步驟 2 - 繫結

在這裡,我們通常指定將在會話的其餘部分使用的使用者名稱和密碼。

以下是使用 DN *dn*、憑據 *pwd* 和繫結方法 *method* 繫結 LDAP 連線的語法:

conn.bind(dn = nil, password = nil, method = LDAP::LDAP_AUTH_SIMPLE)do
....
end

您可以使用相同的方法而不帶程式碼塊。在這種情況下,您需要顯式地取消繫結連線,如下所示:

conn.bind(dn = nil, password = nil, method = LDAP::LDAP_AUTH_SIMPLE)
....
conn.unbind

如果給出了程式碼塊,則將 *self* 傳遞給程式碼塊。

現在,我們可以在 bind 方法的程式碼塊內(bind 和 unbind 之間)執行搜尋、新增、修改或刪除操作,前提是我們具有適當的許可權。

示例

假設我們正在本地伺服器上工作,讓我們將所有內容與相應的主機、域名、使用者 ID 和密碼等組合在一起。

#/usr/bin/ruby -w

require 'ldap'

$HOST =    'localhost'
$PORT =    LDAP::LDAP_PORT
$SSLPORT = LDAP::LDAPS_PORT

conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn = root, dc = localhost, dc = localdomain','secret')
....
conn.unbind

新增 LDAP 條目

新增 LDPA 條目是一個兩步過程 -

步驟 1 - 建立LDAP::Mod物件

我們需要將LDAP::Mod物件傳遞給conn.add方法來建立一個條目。這是一個建立LDAP::Mod物件的簡單語法 -

Mod.new(mod_type, attr, vals)
  • mod_type - 一個或多個選項 LDAP_MOD_ADD、LDAP_MOD_REPLACE 或 LDAP_MOD_DELETE。

  • attr - 應該是要操作的屬性的名稱。

  • vals - 是與attr相關的值的陣列。如果vals包含二進位制資料,則mod_type應邏輯或 (|) 與 LDAP_MOD_BVALUES。

此呼叫返回LDAP::Mod物件,該物件可以傳遞給 LDAP::Conn 類中的方法,例如 Conn#add、Conn#add_ext、Conn#modify 和 Conn#modify_ext。

步驟 2 - 呼叫conn.add方法

準備好LDAP::Mod物件後,我們可以呼叫conn.add方法來建立條目。這是呼叫此方法的語法 -

conn.add(dn, attrs)

此方法使用 DN(dn)和屬性(attrs)新增條目。這裡,attrs應該是一個LDAP::Mod物件的陣列或一個屬性/值陣列對的雜湊。

示例

這是一個完整的示例,它將建立兩個目錄條目 -

#/usr/bin/ruby -w

require 'ldap'

$HOST =    'localhost'
$PORT =    LDAP::LDAP_PORT
$SSLPORT = LDAP::LDAPS_PORT

conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn = root, dc = localhost, dc = localdomain','secret')

conn.perror("bind")
entry1 = [
   LDAP.mod(LDAP::LDAP_MOD_ADD,'objectclass',['top','domain']),
   LDAP.mod(LDAP::LDAP_MOD_ADD,'o',['TTSKY.NET']),
   LDAP.mod(LDAP::LDAP_MOD_ADD,'dc',['localhost']),
]

entry2 = [
   LDAP.mod(LDAP::LDAP_MOD_ADD,'objectclass',['top','person']),
   LDAP.mod(LDAP::LDAP_MOD_ADD, 'cn', ['Zara Ali']),
   LDAP.mod(LDAP::LDAP_MOD_ADD | LDAP::LDAP_MOD_BVALUES, 'sn', 
                     ['ttate','ALI', "zero\000zero"]),
]

begin
   conn.add("dc = localhost, dc = localdomain", entry1)
   conn.add("cn = Zara Ali, dc = localhost, dc =  localdomain", entry2)
rescue LDAP::ResultError
   conn.perror("add")
   exit
end
conn.perror("add")
conn.unbind

修改 LDAP 條目

修改條目類似於新增條目。只需呼叫modify方法而不是add方法,並使用要修改的屬性。這是modify方法的簡單語法。

conn.modify(dn, mods)

此方法使用 DN(dn)和屬性(mods)修改條目。這裡,mods應該是一個LDAP::Mod物件的陣列或一個屬性/值陣列對的雜湊。

示例

要修改我們在上一節中新增的條目的姓氏,我們可以編寫 -

#/usr/bin/ruby -w

require 'ldap'

$HOST =    'localhost'
$PORT =    LDAP::LDAP_PORT
$SSLPORT = LDAP::LDAPS_PORT

conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn = root, dc = localhost, dc = localdomain','secret')

conn.perror("bind")
entry1 = [
   LDAP.mod(LDAP::LDAP_MOD_REPLACE, 'sn', ['Mohtashim']),
]

begin
   conn.modify("cn = Zara Ali, dc = localhost, dc = localdomain", entry1)
rescue LDAP::ResultError
   conn.perror("modify")
   exit
end
conn.perror("modify")
conn.unbind

刪除 LDAP 條目

要刪除條目,請使用其可分辨名稱作為引數呼叫delete方法。這是delete方法的簡單語法。

conn.delete(dn)

此方法使用 DN(dn)刪除條目。

示例

要刪除我們在上一節中新增的Zara Mohtashim條目,我們可以編寫 -

#/usr/bin/ruby -w

require 'ldap'

$HOST =    'localhost'
$PORT =    LDAP::LDAP_PORT
$SSLPORT = LDAP::LDAPS_PORT

conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn = root, dc = localhost, dc = localdomain','secret')

conn.perror("bind")
begin
   conn.delete("cn = Zara-Mohtashim, dc = localhost, dc = localdomain")
rescue LDAP::ResultError
   conn.perror("delete")
   exit
end
conn.perror("delete")
conn.unbind

修改可分辨名稱

無法使用modify方法修改條目的可分辨名稱。相反,請使用modrdn方法。這是modrdn方法的簡單語法 -

conn.modrdn(dn, new_rdn, delete_old_rdn)

此方法使用 DN(dn)修改條目的 RDN,並賦予其新的 RDN(new_rdn)。如果delete_old_rdntrue,則舊的 RDN 值將從條目中刪除。

示例

假設我們有以下條目 -

dn: cn = Zara Ali,dc = localhost,dc = localdomain
cn: Zara Ali
sn: Ali
objectclass: person

然後,我們可以使用以下程式碼修改其可分辨名稱 -

#/usr/bin/ruby -w

require 'ldap'

$HOST =    'localhost'
$PORT =    LDAP::LDAP_PORT
$SSLPORT = LDAP::LDAPS_PORT

conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn = root, dc = localhost, dc = localdomain','secret')

conn.perror("bind")
begin
   conn.modrdn("cn = Zara Ali, dc = localhost, dc = localdomain", "cn = Zara Mohtashim", true)
rescue LDAP::ResultError
   conn.perror("modrdn")
   exit
end
conn.perror("modrdn")
conn.unbind

執行搜尋

要對 LDAP 目錄執行搜尋,請使用search方法和三種不同的搜尋模式之一 -

  • LDAP_SCOPE_BASEM - 只搜尋基本節點。

  • LDAP_SCOPE_ONELEVEL - 搜尋基本節點的所有子節點。

  • LDAP_SCOPE_SUBTREE - 搜尋整個子樹,包括基本節點。

示例

這裡,我們將搜尋條目dc = localhost, dc = localdomain的整個子樹以查詢person物件 -

#/usr/bin/ruby -w

require 'ldap'

$HOST =    'localhost'
$PORT =    LDAP::LDAP_PORT
$SSLPORT = LDAP::LDAPS_PORT

base = 'dc = localhost,dc = localdomain'
scope = LDAP::LDAP_SCOPE_SUBTREE
filter = '(objectclass = person)'
attrs = ['sn', 'cn']

conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn = root, dc = localhost, dc = localdomain','secret')

conn.perror("bind")
begin
   conn.search(base, scope, filter, attrs) { |entry|
      # print distinguished name
      p entry.dn
      # print all attribute names
      p entry.attrs
      # print values of attribute 'sn'
      p entry.vals('sn')
      # print entry as Hash
      p entry.to_hash
   }
rescue LDAP::ResultError
   conn.perror("search")
   exit
end
conn.perror("search")
conn.unbind

這將為每個匹配的條目呼叫給定的程式碼塊,其中 LDAP 條目由 LDAP::Entry 類的例項表示。使用搜索的最後一個引數,您可以指定您感興趣的屬性,省略所有其他屬性。如果您在此處傳遞 nil,則將返回所有屬性,與關係資料庫中的“SELECT *”相同。

LDAP::Entry 類的 dn 方法(get_dn 的別名)返回條目的可分辨名稱,使用 to_hash 方法,您可以獲取其屬性(包括可分辨名稱)的雜湊表示。要獲取條目屬性的列表,請使用 attrs 方法(get_attributes 的別名)。此外,要獲取一個特定屬性值的列表,請使用 vals 方法(get_values 的別名)。

處理錯誤

Ruby/LDAP 定義了兩個不同的異常類 -

  • 如果發生錯誤,新的、繫結或解綁方法將引發 LDAP::Error 異常。

  • 如果新增、修改、刪除或搜尋 LDAP 目錄引發 LDAP::ResultError。

進一步閱讀

有關 LDAP 方法的完整詳細資訊,請參閱LDAP 文件的標準文件。

Ruby - 多執行緒

傳統的程式只有一個執行執行緒,構成程式的語句或指令按順序執行,直到程式終止。

多執行緒程式具有多個執行執行緒。在每個執行緒中,語句都是按順序執行的,但執行緒本身可以在多核 CPU 上並行執行,例如。通常在單 CPU 機器上,多個執行緒實際上並不是並行執行的,而是透過交錯執行執行緒來模擬並行性。

Ruby 使用Thread類使編寫多執行緒程式變得容易。Ruby 執行緒是一種輕量級且高效的方式來實現程式碼中的併發性。

建立 Ruby 執行緒

要啟動一個新執行緒,只需將一個程式碼塊與對Thread.new的呼叫關聯起來。將建立一個新執行緒來執行程式碼塊中的程式碼,並且原始執行緒將立即從Thread.new返回,並使用下一條語句恢復執行 -

# Thread #1 is running here
Thread.new {
   # Thread #2 runs this code
}
# Thread #1 runs this code

示例

這是一個示例,它展示了我們如何使用多執行緒 Ruby 程式。

#!/usr/bin/ruby

def func1
   i = 0
   while i<=2
      puts "func1 at: #{Time.now}"
      sleep(2)
      i = i+1
   end
end

def func2
   j = 0
   while j<=2
      puts "func2 at: #{Time.now}"
      sleep(1)
      j = j+1
   end
end

puts "Started At #{Time.now}"
t1 = Thread.new{func1()}
t2 = Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"

這將產生以下結果 -

Started At Wed May 14 08:21:54 -0700 2008
func1 at: Wed May 14 08:21:54 -0700 2008
func2 at: Wed May 14 08:21:54 -0700 2008
func2 at: Wed May 14 08:21:55 -0700 2008
func1 at: Wed May 14 08:21:56 -0700 2008
func2 at: Wed May 14 08:21:56 -0700 2008
func1 at: Wed May 14 08:21:58 -0700 2008
End at Wed May 14 08:22:00 -0700 2008

執行緒生命週期

使用Thread.new建立新的執行緒。您還可以使用同義詞Thread.startThread.fork

建立執行緒後無需啟動它,它會在 CPU 資源可用時自動開始執行。

Thread 類定義了許多方法來查詢和操作正在執行的執行緒。執行緒執行與對Thread.new的呼叫關聯的程式碼塊中的程式碼,然後停止執行。

該程式碼塊中最後一個表示式的值是執行緒的值,可以透過呼叫 Thread 物件的value方法來獲取。如果執行緒已執行完成,則value方法會立即返回值。否則,value方法會阻塞,並且不會返回,直到執行緒完成。

類方法Thread.current返回表示當前執行緒的 Thread 物件。這允許執行緒自行操作。類方法Thread.main返回表示主執行緒的 Thread 物件。這是在 Ruby 程式啟動時開始的初始執行執行緒。

您可以透過呼叫該執行緒的Thread.join方法來等待特定執行緒完成。呼叫執行緒將阻塞,直到給定執行緒完成。

執行緒和異常

如果在主執行緒中引發異常,並且在任何地方都沒有處理,則 Ruby 直譯器會列印一條訊息並退出。在除主執行緒之外的其他執行緒中,未處理的異常會導致執行緒停止執行。

如果執行緒t由於未處理的異常而退出,並且另一個執行緒s呼叫t.join或t.value,則在t中發生的異常將線上程s中引發。

如果Thread.abort_on_exceptionfalse(預設條件),則未處理的異常只會終止當前執行緒,其餘執行緒將繼續執行。

如果您希望任何執行緒中的任何未處理異常導致直譯器退出,請將類方法Thread.abort_on_exception設定為true

t = Thread.new { ... }
t.abort_on_exception = true

執行緒變數

執行緒通常可以訪問建立執行緒時處於作用域內的任何變數。執行緒程式碼塊中的區域性變數是執行緒的區域性變數,並且不共享。

Thread 類提供了一個特殊的功能,允許透過名稱建立和訪問執行緒區域性變數。您只需將執行緒物件視為雜湊表,使用[]=寫入元素,並使用[]讀取它們。

在此示例中,每個執行緒將變數 count 的當前值記錄在具有鍵mycount的執行緒區域性變數中。

即時演示
#!/usr/bin/ruby

count = 0
arr = []

10.times do |i|
   arr[i] = Thread.new {
      sleep(rand(0)/10.0)
      Thread.current["mycount"] = count
      count += 1
   }
end

arr.each {|t| t.join; print t["mycount"], ", " }
puts "count = #{count}"

這將產生以下結果 -

8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10

主執行緒等待子執行緒完成,然後打印出每個執行緒捕獲的count值。

執行緒優先順序

影響執行緒排程的第一個因素是執行緒優先順序:高優先順序執行緒優先於低優先順序執行緒排程。更準確地說,只有在沒有更高優先順序的執行緒等待執行時,執行緒才會獲得 CPU 時間。

您可以使用priority =priority設定和查詢 Ruby Thread 物件的優先順序。新建立的執行緒以建立它的執行緒相同的優先順序啟動。主執行緒從優先順序 0 開始。

無法線上程開始執行之前設定其優先順序。但是,執行緒可以將其自身的優先順序作為其採取的第一個操作提高或降低。

執行緒互斥

如果兩個執行緒共享對同一資料的訪問,並且至少一個執行緒修改該資料,則必須特別注意確保任何執行緒都無法看到資料處於不一致的狀態。這稱為執行緒互斥

Mutex是一個實現簡單訊號量鎖的類,用於對某些共享資源進行互斥訪問。也就是說,在任何給定時間只有一個執行緒可以持有鎖。其他執行緒可以選擇排隊等待鎖可用,或者可以選擇立即獲取一個指示鎖不可用的錯誤。

透過將對共享資料的訪問都置於mutex的控制之下,我們確保了一致性和原子操作。讓我們嘗試兩個示例,第一個沒有 mutax,第二個有 mutax -

無 Mutex 示例

即時演示
#!/usr/bin/ruby
require 'thread'

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      count1 += 1
      count2 += 1
   end
end
spy = Thread.new do
   loop do
      difference += (count1 - count2).abs
   end
end
sleep 1
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

這將產生以下結果:

count1 :  1583766
count2 :  1583766
difference : 0
即時演示
#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      mutex.synchronize do
         count1 += 1
         count2 += 1
      end
   end
end
spy = Thread.new do
   loop do
      mutex.synchronize do
         difference += (count1 - count2).abs
      end
   end
end
sleep 1
mutex.lock
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

這將產生以下結果:

count1 :  696591
count2 :  696591
difference : 0

處理死鎖

當我們開始使用Mutex物件進行執行緒互斥時,必須小心避免死鎖。死鎖是指當所有執行緒都在等待獲取另一個執行緒持有的資源時發生的情況。因為所有執行緒都被阻塞,所以它們無法釋放它們持有的鎖。並且因為它們無法釋放鎖,所以其他執行緒也無法獲取這些鎖。

這就是條件變數發揮作用的地方。條件變數只是一個與資源關聯的訊號量,並在特定mutex的保護下使用。當您需要一個不可用的資源時,您將在條件變數上等待。該操作會釋放相應mutex上的鎖。當其他一些執行緒發出訊號表明資源可用時,原始執行緒將停止等待並同時重新獲得臨界區域上的鎖。

示例

即時演示
#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

cv = ConditionVariable.new
a = Thread.new {
   mutex.synchronize {
      puts "A: I have critical section, but will wait for cv"
      cv.wait(mutex)
      puts "A: I have critical section again! I rule!"
   }
}

puts "(Later, back at the ranch...)"

b = Thread.new {
   mutex.synchronize {
      puts "B: Now I am critical, but am done with cv"
      cv.signal
      puts "B: I am still critical, finishing up"
   }
}
a.join
b.join

這將產生以下結果:

A: I have critical section, but will wait for cv
(Later, back at the ranch...)
B: Now I am critical, but am done with cv
B: I am still critical, finishing up
A: I have critical section again! I rule!

執行緒狀態

有五個可能的返回值對應於五種可能的狀態,如下表所示。status方法返回執行緒的狀態。

執行緒狀態 返回值
可執行 run
睡眠 睡眠
中止 aborting
正常終止 false
異常終止 nil

Thread 類方法

Thread類提供了以下方法,它們適用於程式中所有可用的執行緒。這些方法將透過使用Thread類名如下呼叫 -

Thread.abort_on_exception = true

執行緒例項方法

這些方法適用於執行緒的例項。這些方法將被呼叫,如下所示,使用Thread的例項 -

#!/usr/bin/ruby

thr = Thread.new do   # Calling a class method new
   puts "In second thread"
   raise "Raise exception"
end
thr.join   # Calling an instance method join

Ruby - 內建函式

由於Kernel模組被Object類包含,因此它的方法在Ruby程式中的任何地方都可用。它們可以在沒有接收者的情況下呼叫(函式形式)。因此,它們通常被稱為函式。

數字函式

以下是與數字相關的內建函式列表。它們應按以下方式使用:

即時演示
#!/usr/bin/ruby

num = 12.40
puts num.floor      # 12
puts num + 10       # 22.40
puts num.integer?   # false  as num is a float.

這將產生以下結果:

12
22.4
false

浮點數函式

數學函式

轉換欄位說明符

函式sprintf( fmt[, arg...]) 和 format( fmt[, arg...])返回一個字串,其中 arg 根據 fmt 進行格式化。格式化規範與 C 程式語言中 sprintf 的格式化規範基本相同。fmt 中的轉換說明符(% 後跟轉換欄位說明符)將替換為對應引數的格式化字串。

以下是用法示例:

即時演示
#!/usr/bin/ruby

str = sprintf("%s\n", "abc")   # => "abc\n" (simplest form)
puts str 

str = sprintf("d=%d", 42)      # => "d=42" (decimal output)
puts str 

str = sprintf("%04x", 255)     # => "00ff" (width 4, zero padded)
puts str 

str = sprintf("%8s", "hello")  # => " hello" (space padded)
puts str 

str = sprintf("%.2s", "hello") # => "he" (trimmed by precision)
puts str 

這將產生以下結果:

abc
d = 42
00ff
   hello
he

測試函式引數

函式test( test, f1[, f2])執行以下由字元test指定的其中一個檔案測試。為了提高可讀性,您應該使用 File 類方法(例如,File::readable?)而不是此函式。

以下是用法示例。假設 main.rb 存在,具有讀、寫許可權,但不具有執行許可權:

即時演示
#!/usr/bin/ruby

puts test(?r, "main.rb" )   # => true
puts test(?w, "main.rb" )   # => true
puts test(?x, "main.rb" )   # => false

這將產生以下結果:

true
false
false

Ruby - 預定義變數

Ruby 的預定義變數會影響整個程式的行為,因此不建議在庫中使用它們。

大多數預定義變數中的值可以透過其他方式訪問。

下表列出了所有 Ruby 的預定義變數。

序號 變數名和描述
1

$!

最後引發的異常物件。也可以在rescue子句中使用=>訪問異常物件。

2

$@

最後引發的異常的堆疊回溯。可以透過最後異常的 Exception#backtrace 方法檢索堆疊回溯資訊。

3

$/

輸入記錄分隔符(預設為換行符)。gets、readline等將它們可選的引數作為輸入記錄分隔符。

4

$\

輸出記錄分隔符(預設為 nil)。

5

$,

print 和 Array#join 的引數之間的輸出分隔符(預設為 nil)。您可以為 Array#join 顯式指定分隔符。

6

$;

split 的預設分隔符(預設為 nil)。您可以為 String#split 顯式指定分隔符。

7

$.

從當前輸入檔案讀取的最後一行編號。等效於 ARGF.lineno。

8

$<

ARGF 的同義詞。

9

$>

$defout 的同義詞。

10

$0

正在執行的當前 Ruby 程式的名稱。

11

$$

正在執行的當前 Ruby 程式的程序 pid。

12

$?

最後一個終止程序的退出狀態。

13

$:

$LOAD_PATH 的同義詞。

14

$DEBUG

如果指定了 -d 或 --debug 命令列選項,則為真。

15

$defout

printprintf 的目標輸出(預設情況下為 $stdout)。

16

$F

當指定 -a 時,接收來自 split 的輸出的變數。如果指定了 -a 命令列選項以及 -p 或 -n 選項,則設定此變數。

17

$FILENAME

當前從 ARGF 讀取的檔案的名稱。等效於 ARGF.filename。

18

$LOAD_PATH

一個數組,其中包含在使用 load 和 require 方法載入檔案時要搜尋的目錄。

19

$SAFE

安全級別

0 → 對外部提供的(受汙染的)資料不執行任何檢查。(預設值)

1 → 禁止使用受汙染的資料進行潛在的危險操作。

2 → 禁止對程序和檔案的潛在危險操作。

3 → 所有新建立的物件都被視為受汙染的。

4 → 禁止修改全域性資料。

20

$stdin

標準輸入(預設為 STDIN)。

21

$stdout

標準輸出(預設為 STDOUT)。

22

$stderr

標準錯誤(預設為 STDERR)。

23

$VERBOSE

如果指定了 -v、-w 或 --verbose 命令列選項,則為真。

24

$- x

直譯器選項 -x 的值 (x=0, a, d, F, i, K, l, p, v)。這些選項列在下面

25

$-0

直譯器選項 -x 的值以及 $/ 的別名。

26

$-a

直譯器選項 -x 的值,如果設定了選項 -a 則為真。只讀。

27

$-d

直譯器選項 -x 的值以及 $DEBUG 的別名

28

$-F

直譯器選項 -x 的值以及 $; 的別名。

29

$-i

直譯器選項 -x 的值,在就地編輯模式下,儲存副檔名,否則為 nil。可以啟用或停用就地編輯模式。

30

$-I

直譯器選項 -x 的值以及 $: 的別名。

31

$-l

直譯器選項 -x 的值,如果設定了選項 -l 則為真。只讀。

32

$-p

直譯器選項 -x 的值,如果設定了選項 -p 則為真。只讀。

33

$_

區域性變數,當前作用域中 gets 或 readline 讀取的最後一個字串。

34

$~

區域性變數,與最後一次匹配相關的 MatchData。Regex#match 方法返回最後一次匹配資訊。

35

$ n ($1, $2, $3...)

在最後一次模式匹配的第 n 個組中匹配的字串。等效於 m[n],其中 m 是一個 MatchData 物件。

36

$&

在最後一次模式匹配中匹配的字串。等效於 m[0],其中 m 是一個 MatchData 物件。

37

$`

在最後一次模式匹配中匹配之前的字串。等效於 m.pre_match,其中 m 是一個 MatchData 物件。

38

$'

在最後一次模式匹配中匹配之後的字串。等效於 m.post_match,其中 m 是一個 MatchData 物件。

39

$+

在最後一次模式匹配中與最後成功匹配的組對應的字串。

Ruby - 預定義常量

下表列出了所有 Ruby 的預定義常量 -

注意 - TRUE、FALSE 和 NIL 向後相容。最好使用 true、false 和 nil。

序號 常量名稱和描述
1

TRUE

true 的同義詞。

2

FALSE

false 的同義詞。

3

NIL

nil 的同義詞。

4

ARGF

一個物件,提供對作為命令列引數傳遞的檔案或標準輸入的虛擬連線的訪問,如果沒有任何命令列引數,則為標準輸入。$< 的同義詞。

5

ARGV

一個數組,包含傳遞給程式的命令列引數。$* 的同義詞。

6

DATA

用於讀取 __END__ 指令後代碼行的輸入流。如果程式碼中不存在 __END__,則未定義。

7

ENV

一個類似雜湊的物件,包含程式的環境變數。ENV 可以作為雜湊處理。

8

RUBY_PLATFORM

一個字串,指示 Ruby 直譯器的平臺。

9

RUBY_RELEASE_DATE

一個字串,指示 Ruby 直譯器的釋出日期

10

RUBY_VERSION

一個字串,指示 Ruby 直譯器的版本。

11

STDERR

標準錯誤輸出流。$stderr 的預設值。

12

STDIN

標準輸入流。$stdin 的預設值。

13

STDOUT

標準輸出流。$stdout 的預設值。

14

TOPLEVEL_BINDING

Ruby 頂層的繫結物件。

Ruby - 相關工具

標準 Ruby 工具

標準 Ruby 發行版包含有用的工具以及直譯器和標準庫 -

這些工具可以幫助您除錯和改進 Ruby 程式,而無需花費太多精力。本教程將為您提供一個很好的開始。

  • RubyGems -

    RubyGems 是 Ruby 的一個包實用程式,它安裝 Ruby 軟體包並保持其最新狀態。

  • Ruby 偵錯程式 -

    為了幫助處理錯誤,Ruby 的標準發行版包含一個偵錯程式。這與 gdb 實用程式非常相似,可用於除錯複雜程式。

  • 互動式 Ruby (irb) -

    irb(互動式 Ruby)由 Keiju Ishitsuka 開發。它允許您在提示符處輸入命令,並讓直譯器做出響應,就像您正在執行程式一樣。irb 可用於實驗或探索 Ruby。

  • Ruby 分析器 -

    Ruby 分析器可幫助您透過查詢瓶頸來提高緩慢程式的效能。

其他 Ruby 工具

還有一些有用的工具沒有與 Ruby 標準發行版捆綁在一起。但是,您需要自己安裝它們。

  • eRuby:嵌入式 Ruby -

    eRuby 代表嵌入式 Ruby。它是一個工具,可以將 Ruby 程式碼片段嵌入到其他檔案中,例如 HTML 檔案,類似於 ASP、JSP 和 PHP。

  • ri:Ruby 互動式參考 -

    當您對某個方法的行為有疑問時,您可以呼叫 ri 來閱讀該方法的簡要說明。

有關 Ruby 工具和資源的更多資訊,請檢視 Ruby 有用資源

廣告
© . All rights reserved.