Thứ Năm, 4 tháng 12, 2008

Sơ lược về Ruby

Ruby in little view

1. Ruby

Ruby được phát triển bởi một người Nhật bản tên là Yukihiro Matsumoto. Là một ngôn ngữ lập trình động kiểu thông dịch, Ruby khá phức tạp về mặt cú pháp nhưng lại đem lại nhiều ấn tượng về các thư viện gốc với các giao diện lập trình ứng dụng khá mạnh mẽ.

Ruby được nhiều người đánh giá là giống với Lisp (L), Smalltalk(L) và Perl nhưng sử dụng cấu trúc cú pháp của Java và C.

2. Inside Ruby

Cũng như các ngôn ngữ lập trình khác, Ruby cũng có các quy định về cú pháp, kiểu dữ liệu, các cấu trúc điều khiển luồng, các toán tử…

Ruby Fundamentals

a. Cấu trúc một chương trình Ruby

Là một dạng của ngôn ngữ lập trình thế hệ thứ 3 (3GL: 3rd Generation Language), một trương trình Ruby bao gồm các thư viện liên kết và các đoạn mã được phân chia theo khối ( code block). Bên cạnh đó với đặc điểm là ngôn ngữ thông dịch được viết theo dạng script, chương trình không cần hàm main mà được thực thi theo thứ tự các dòng mã.

Một chương trình có thể lưu trong nhiều tập tin mã nguồn khác nhau và được sử dụng lại thông qua cấu trúc lệnh : require hoặc path

Khai báo trong Ruby không quá phức tạp như các ngôn ngữ khác vì không yêu cầu xác định kiểu dữ liệu trong cấu trúc khai báo.

Ví dụ:

myString = 'This is my String'

myInt = 5

b. Các dạng dữ liệu và đối tượng

Ruby là một ngôn ngữ hướng đối tượng 100%. Ở đây các thành phần dữ liệu từ số, ký tự, mảng…. đều được xây dựng trên cơ sở các lớp.

Số:

Cấu trúc phân cấp dữ liệu dạng số trong Ruby:

Các dạng dữ liệu kiểu số được xây dựng từ lớp Numeric. Kiểu số nguyên : Integer có hai dạng là Fixnum với độ dài 31 bits và Bignum có độ dài tùy ý. Kiểu số thực được thể hiện qua lớp Float. Bên cạnh đó một số kiểu dữ liệu khác không có sẵn nhưng được định nghĩa trong các thư viện chuẩn của Ruby.

Ký tự

String là lớp dùng để thể hiện chuỗi ký tự. Khác với Java String trong Ruby là “mutable . String trong Ruby có thể được khai báo trong dấu ngoặc đơn hoặc ngoặc kép. Với dạng chuỗi được đặt trong dấu nháy đơn ‘’ thì ký tự \ chỉ có ý nghĩa khi sau nó là ký tự \ hoặc ‘. Bên cạnh đó chuỗi trong nháy đơn được viết xuống dòng thì nó sẽ được hiển thị thành nhiều dòng tương ứng.

Với dạng chuối trong dấu nháy kép “” thì nhiều ký tự đặc biệt được hỗ trợ, ví dụ như \n, \t như trong java. Bên cạnh đó chuối trong dấu nháy kép còn có thể hiện thị kết quả của biểu thức trong nó thông qua ký tự #. Ví dụ :

string = "So Pi co gia tri la #{Math::PI}"

puts string

Sẽ hiển thị kết quả là: So Pi co gia tri la 3.14159265358979

Mảng

Mảng có thể khai báo trực tiếp hoặc thông qua đối tượng Array.

arr = [1,2,3,4,5,6]

arr = Array.new

Cách đánh chỉ số mảng trong Ruby cũng tương tự như trong java tức là từ 0 đến số phần tử -1. Tuy nhiên có một điều khác biệt ở chố các chỉ số <0.>

Một điểm đặc biệt nữa là trong Ruby, việc sắp xếp các thành phần mảng khá linh hoạt và mềm dẻo. Ta có thể khai báo mảng một chiều gồm các phần tử đơn: arr = [1,2,3,4,5,6]. Hoặc mảng lồng: arr = [[1,2],[3,4,5,6],[7,8,9]]. Hoặc mảng được trích xuất subArr = arr[0,2] #subArr = [[1,2],[3,4,5,6]].

Các mảng có thể tương tác với nhau thông qua các toán tử như +,-,*…

Với phép + ta có thể cộng hai mảng với nhau: ar= [1,2,3] +[4] # ar=[1,2,3,4]

Với phép trừ các phần tử mảng ở mảng trừ sẽ loại bỏ các phần tử có trong mảng bị trừ.

ar= [1,2,3] -[2] # ar=[1,3]

Với phép nhân, ta có thể nhân một mảng với một số và kết quả cho ta số phần tử mảng được lặp lại theo giá trị được nhân: ar= [1,2,3]*2 # ar= [1,2,3,1,2,3]

Các mảng có thể đính thêm phần tử với phép toán <<: ar= [1,2,3]<<4 # ar= [1,2,3,4]

Và các phép so sánh: |, &. Với | các giá trị trùng lặp của hai mảng sẽ được bỏ đi ( kể cả các phần tử trùng lặp trong 1 mảng. ar = [1,2,2,4,3,4] | [] # ar[1,2,4,3]. Trong khi đó với phép toán & các phần tử trùng nhau được giữ lại ( và không lặp). ar = [1,2,2,4,3,4] & [4,4] # ar[4]

c. Toán tử trong Ruby

Bảng dưới đây mô tả các toán tử trong Ruby với thứ tự ưu tiên từ cao xuống thấp

N: Số toán hạng

A: Thứ tự thực hiện (L: trái sang phải, R: phải sang trái)

Toán t

N

A

Ghi chú

! ~ +

1

R

Toán tử phủ định, bù bit, phép cộng một toán hạng

**

2

R

Phép lũy thừa

-

1

R

Phép trừ một toán hạng

* / %

2

L

Phép nhân, chia, lấy số dư

+ -

2

L

Phép cộng, trừ ( hai toán hạng)

<< >>

2

L

Phép dịch bit (trái, phải)

&

2

L

Phép AND các bit

| ^

2

L

Phép OR và XOR các bit

< <= >= >

2

L

So sánh hơn kém (hoặc bằng)

== === != =~ !~ <=>

2

N

So sánh bằng, so sánh kiểu case, so sánh khác, hợp mẫu, so sánh

&&

2

L

Phép AND logic

||

2

L

Phép OR logic

.. ...

2

N

Dải giá trị và flip-flop

?:

3

R

Điều kiện

rescue

2

L

Bổ nghĩa ngoại lệ

=
**= *= /= %= += -=
<<= >>=
&&= &= ||= |= ^=

2

R

Phép gán

not

1

R

Phép phủ định logic ( ưu tiên thấp)

and or

2

L

Phép AND, OR logic (ưu tiên thấp)

d. Các cấu trúc điều khiển

d1. Các cấu trúc điều kiện

if

if <<điều kiện>>

<>

end

<> if <<điều kiện>>

if-else

if <<điều kiện>>

<>

else

<>

end

elsif

if <<điều kiện>>

<>

elsif<<điều kiện>>

<>

elsif<<điều kiện>>

<>

end

unless

unless <<điều kiện>>

<>

end

unless cũng có thể được sử dụng với else như trường hợp của if.

case

Case trong Ruby không lằng nhằng như trong java ( quên break là cả một vấn đề rồi). Ở đây có thể sử dụng cấu trúc elseif để đưa ra khối điều khiển giống như trong khối điều khiển case, tuy nhiên cú pháp case vấn thường được sử dụng nhiều hơn.

case

when <> then <>

when <> then <>

when <> then <>

end

Chú ý là ở đây nếu có nhiều hơn một điều kiện đúng thì hành động của điều kiện đầu tiên sẽ được thực hiện

Ví dụ

x=1

a=case

when x>0 then

puts "x is 1"

puts "hehe"

when x==2 then puts "x is 2"

when x<3 then "three"

end

puts a

Kết quả sẽ là

x is 1

hehe

nil

* cấu trúc ?: trong Ruby giống như trong java nhưng được mô tả như cấu trúc if với ? là then và : là else J

d2. Các cấu trúc lặp và liệt kê

while

while <> do

<>

End

begin

<>

while <>

util

util <<condition>> do

<<actions>>

End

begin

<<actions>>

end util <<conditions>>

for

for <<variables>> in <<collection>> do

<<actions>>

end

Cấu trúc liệt kê

+ Với đối tượng số

upto/downto

0.upto(9){|s| print s}

times

10.times{|s| print s}

step

0.step(9,1){|x| print x}

+ Với Hash, Array, Range

each

(1..9).each{|s| print s}

Result: 123456789

collect

result = (2..4).collect{|s| s*s*s}

puts result

Result:

8

27

64

select

positive = [1,-2,3,4,-9].select{|s| s>0}

puts positive

Result:

1

3

4

reject

negative = [1,-2,3,4,-9].reject{|s| s>0}

puts negative

Result:

-2

-9

d3. Ngoại lệ

Ngoại lệ và cách điều khiển ngoại lệ trong Ruby có phần khá giống với Java với raise ~throw try-catch~begin-rescue-end

Một số ví dụ

Ruby

Java

def factorialOf(n)

raise ArgumentError, "Wrong argument" if n <0

factorial =1

1.upto(n){|x| factorial*=x}

return factorial

end

begin

factorialOf(-1)

rescue ArgumentError=>ex

puts ex.message

end

public static long factorialOf(int n) throws Exception{

if(n<0)>throw new Exception("Wrong argument");

long factorial=1;

for(int i=0;i

return factorial;

}

public static void main(String args[]){

try{

System.out.println(factorialOf(-1));

}catch(Exception ex){ System.out.println(ex.toString());

}

}

Wrong argument

java.lang.Exception: Wrong argument

d4. Các từ khóa điều khiển

Ruby cũng cung cấp một số từ khóa hỗ trợ điều khiển cấu trúc chương trình như: return, break, next, redo, retry, throw/catch

d5. Blocks

Trong quá trình sử dụng các cấu trúc liệt kê, chúng ta thường thấy một nhóm các câu lệnh nằm trong cặp ngoặc nhọn hoặc trong long khối begin/end. Người ta gọi đó là block. Thông thường block bao giờ cũng được thực hiện sau lời gọi hàm

Ví dụ:

10.downto(0){|x| print x}

Ở đây khối |x| print x được thực hiện sau lời gọi hàm và đó là block. Theo quy ước thì với với block trong phạm vi một dòng ta nên dùng ngoặc nhọn còn với block có nhiều dòng ta nên sử dụng do .. end

Chú ý là trong block, giá trị trả về được thông qua câu lệnh next chứ không phải là return (chỉ trả về giá trị cho hàm đóng).

e. Methods, procs, lamdas và closures

Phương thức có cú pháp như sau:

def <> (<>)

Ví dụ:

def squareRootOf(n,loop)

ini = n/2

loop.times {ini = (n/ini + ini)/2}

return ini

end

Một điểm đặc biệt ở đây là nhiều giá trị có thể đồng thời được trả về trong một phương thức. Các giá trị trả về sẽ được tập hợp trong một mảng.

Ví dụ:

def multiValuesReturn()

return 1, 'hello', 1.4

end

arr = multiValuesReturn

arr.each {|x| print x}

procs và lambdas

procslambdas là hai cách thức để đưa blocks vào trong đối tượng. Tùy thuộc vào cách mà đối tượng được tạo ra ta sẽ có procs hay lambdas.

Tạo procs

def createProcs(&p)

p

end

exp = createProcs{|x,y| x**y}

Hoặc

exp = Proc.new{|x,y| x**y}

Gọi procs

puts exp.call(2,3)

Tạo lambdas

incre = lambda{|x| x+1}

hoặc

incre= ->(x){x+1} # ruby version 1.9

hoặc

incre=->(x;step=2){x+step} # Một tham số x và biến nội bộ step

Gọi lambdas

puts incre.call(2)

Closures

Closures là một khái niệm chỉ một hàm sử dụng một biến giới hạn. Thông thường closures dùng để nói đến hàm lồng. Ở đó hàm bên trong sử dụng biến được khai báo bởi hàm chứa nó. Ở Ruby, khái niệm này thường được thể hiện bởi các khối lambdas hoặc procs.

Ví dụ

def mainFunction(n,m)

lambda{|x| x*n/m}

end

myLambda = mainFunction(2,4)

puts myLambda.call(2)

Kết quả ở đây là 1

f. Lớp và modules

Là một ngôn ngữ hướng đối tượng, khái niệm lớp là thành phần cơ bản trong Ruby. Lớp được khai báo như sau:

class <<name_of_class>>

<<body_of_class>>

end

Khới tạo class

<<name_of_class>>.new

Hàm khởi tạo trong lớp. ( giống như hàm tạo và khởi tạo giá trị trong java)

def initialize(<<var1>>,<<var2>>)

<<khới tạo các giá trị>>

end

Đối với các hàm việc xác định khả năng truy cập được thông qua các từ khóa public , private, protected giống như Java. Tuy nhiên ở Java chúng ta có thêm default và được coi như mặc định trong khai báo còn ở đây public được coi là mặc định trong khai báo. Public cho phép các hàm được truy nhập từ bất kỳ đâu trong khi private chỉ cho các hàm được truy nhập từ các thành phần khác trong lớp đó và các lớp con của nó, protected giống private chỉ khác ở chỗ các hàm protected có thể được gọi bởi các thực thể của chính lớp đó hoặc với sefl.

class Test

private

def myTest()

puts "test"

end

protected

def proTest()

puts "pro"

end

public

def testTest()

theTest = Test.new

theTest.proTest()

end

def testPrivate()

theTest = Test.new

theTest.myTest()

end

end

a = Test.new

a.testTest()# =>pro

a.testPrivate()#=> error in red as below

Kết quả:

pro

HelloWorld.rb:20:in `testPrivate': private method `myTest' called for # (NoMethodError)

from HelloWorld.rb:28

Bên cạnh đó ở Ruby các biến trong lớp đều được đặt là private, trong khi các hằng số đều là public.

Thừa kế trong Ruby

Là ngôn ngữ hướng đối tượng nên Ruby có đầy đủ các tính chất như tính đa hình, đóng gói… và kế thừa

class Parent

def printOut

puts "This is Parent class"

end

end

class Child <>

def printOut

puts "This is Child Class"

end

end

Modules

Modules là nhóm các thành phần hàm, biến, hằng số và chạy độc lập

module MyModule

def MyModule.intro

puts "This is the intro of modul"

end

def MyModule.sayHello

puts "Hello"

end

end

class MyClass

include(MyModule)

def sayHello

MyModule.sayHello

end

end

myClass = MyClass.new

myClass::sayHello

Một chương trình có thế gồm nhiều file, và với ngôn ngữ script như Ruby thì việc phân chia chương trình thành các file chứa các module khác nhau.Các file này sau đó có thể được sử dụng thông qua lời gọi require hoặc load trong chương trình chính.

3. Phát triển ứng dụng Ruby với Eclipse

Mặc dù được phát triển từ hơn một thập kỷ trước ở Nhật và được đánh giá là một trong những ngôn ngữ lập trình hướng đối tượng khá mạnh nhưng Ruby dường như vẫn được ít người biết đến. Lý do chính là chưa có môi trường phát triển phù hợp cho việc xây dựng các ứng dụng lớn đòi hỏi nhiều tính năng hỗ trợ.

Ruby Development Tools là mội trường phát triển cho các ứng dụng Ruy. RDT có ưu điểm là mã nguồn mở và có khả năng tích hợp với Eclipse. Với RDT, việc xây dựng các ứng dụng trên nền ngôn ngữ Ruby sẽ dễ dàng hơn nhờ các tính năng hỗ trợ soạn thảo, thông dịch và debug.

Tích hợp RDT

- Mở Eclipse

- Chọn Help---Software Update---Find and Install

- Chọn Search for new features install --- New Remote Site

- Nhập vào: http://updatesite.rubypeople.org/release

- OK --- Finish

Bắt đầu một ứng dụng Ruby

- File----New ---- Ruby Project

Chuot phai <> --- New ---Ruby File

Tạo class

Chuột phải vào project và chọn New---Ruby Class

Tuy nhiên, là ngôn ngữ thông dịch nên việc khai báo class có thể thực hiện tùy ý trong chương

trình.

Chạy Ruby

Chuột phải vào đoạn mã và chọn Run As—Ruby Application


Debuging

Trước hết đặt vào các Break Point, chuột phải vào mã nguồn, chọn Debug As, Ruby Application


Testing

Nếu như với java, nhiều người quen thuộc vơi JUnit thì ở Ruby Unit Test là test framework được sử dụng khá thông dụng



Không có nhận xét nào: