SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
11.
什麼強?弱?分型
i=1
puts "Value is " + i
#TypeError: can't convert Fixnum into
String
# from (irb):2:in `+'
# from (irb):2
$i = 1;
echo "Value is " + $i
# 1
PHP code: Ruby code:
int a = 5;
float b = a;
C code:
37.
控制結構 Case
case name
when "John"
puts "Howdy John!"
when "Ryan"
puts "Whatz up Ryan!"
else
puts "Hi #{name}!"
end
38.
迴圈
while, loop, until, next and break
i = 0
loop do
i += 1
break if i > 10 # 中斷迴圈
end
i=0
while ( i < 10 )
i += 1
next if i % 2 == 0 #跳過雙數
end
i = 0
i += 1 until i > 10
puts i
# 輸出 11
39.
真或假
只有 false 和 nil 是假,其他為真
puts "not execute" if nil
puts "not execute" if false
puts "execute" if true # 輸出 execute
puts "execute" if “” # 輸出 execute (和JavaScript不同)
puts "execute" if 0 # 輸出 execute (和C不同)
puts "execute" if 1 # 輸出 execute
puts "execute" if "foo" # 輸出 execute
puts "execute" if Array.new # 輸出 execute
40.
Regular Expressions
與 Perl 接近的語法
# 抓出⼿手機號碼
phone = "123-456-7890"
if phone =~ /(d{3})-(d{3})-(d{4})/
ext = $1
city = $2
num = $3
end
41.
⽅方法定義 Methods
def 開頭 end 結尾
def say_hello(name)
result = "Hi, " + name
return result
end
puts say_hello('ihower')
# 輸出 Hi, ihower
42.
⽅方法定義 Methods
def 開頭 end 結尾
def say_hello(name)
result = "Hi, " + name
return result
end
puts say_hello('ihower')
# 輸出 Hi, ihower
字串相加
43.
⽅方法定義 Methods
def 開頭 end 結尾
def say_hello(name)
result = "Hi, " + name
return result
end
puts say_hello('ihower')
# 輸出 Hi, ihower
字串相加
return 可省
略,最後⼀一⾏行
就是回傳值
46.
類別 Class
class Person
def initialize(name)
@name = name
end
def say(word)
puts "#{word}, #{@name}"
end
end
p1 = Person.new("ihower")
p2 = Person.new("ihover")
p1.say("Hello") # 輸出 Hello, ihower
p2.say("Hello") # 輸出 Hello, ihover
47.
類別 Class
class Person
def initialize(name)
@name = name
end
def say(word)
puts "#{word}, #{@name}"
end
end
p1 = Person.new("ihower")
p2 = Person.new("ihover")
p1.say("Hello") # 輸出 Hello, ihower
p2.say("Hello") # 輸出 Hello, ihover
建構式
48.
類別 Class
class Person
def initialize(name)
@name = name
end
def say(word)
puts "#{word}, #{@name}"
end
end
p1 = Person.new("ihower")
p2 = Person.new("ihover")
p1.say("Hello") # 輸出 Hello, ihower
p2.say("Hello") # 輸出 Hello, ihover
建構式
物件變數
49.
類別 Class
class Person
def initialize(name)
@name = name
end
def say(word)
puts "#{word}, #{@name}"
end
end
p1 = Person.new("ihower")
p2 = Person.new("ihover")
p1.say("Hello") # 輸出 Hello, ihower
p2.say("Hello") # 輸出 Hello, ihover
建構式
物件變數
字串相加
50.
類別 Class
class Person
def initialize(name)
@name = name
end
def say(word)
puts "#{word}, #{@name}"
end
end
p1 = Person.new("ihower")
p2 = Person.new("ihover")
p1.say("Hello") # 輸出 Hello, ihower
p2.say("Hello") # 輸出 Hello, ihover
建構式
物件變數
字串相加
⼤大寫開頭的
常數
51.
類別 Class (續)
class Person
@@name = “ihower”
def self.say
puts @@name
end
end
Person.say # 輸出 Hello, ihower
52.
類別 Class (續)
class Person
@@name = “ihower”
def self.say
puts @@name
end
end
Person.say # 輸出 Hello, ihower
類別變數
53.
類別 Class (續)
class Person
@@name = “ihower”
def self.say
puts @@name
end
end
Person.say # 輸出 Hello, ihower
類別變數
類別⽅方法
54.
資料封裝
• 所有的物件變數(@開頭)、類別變數(@@開頭),
都是封裝在類別內部,類別外無法存取。
• 需透過定義 public ⽅方法才可以存取到
class Person
def initialize(name)
@name = name
end
end
p = Person.new('ihower')
p.name
=> NoMethodError
p.name='peny'
=> NoMethodError
55.
class Person
def initialize(name)
@name = name
end
def name
@name
end
def name=(name)
@name = name
end
end
p = Person.new('ihower')
p.name
=> "ihower"
p.name="peny"
=> "peny"
56.
⽅方法封裝
預設是 public 公開
class MyClass
def public_method
end
def private_method
end
def protected_method
end
public :public_method
private :private_method
protected :proected_method
end
class MyClass
def public_method
end
private
def private_method
end
protected
def protected_method
end
end
57.
類別 Class body 也可以執⾏行程式
attr_accessor, attr_writer, attr_reader
class Person
attr_accessor :name
end
class Person
def name
@name
end
def name=(val)
@name = val
end
end
等同於
58.
Class 繼承
class Pet
attr_accessor :name, :age
end
class Cat < Pet
end
class Dog < Pet
end
59.
Module (1) Namespace
module MyUtil
def self.foobar
puts "foobar"
end
end
MyUtil.foobar
# 輸出 foobar
60.
Module(2) Mixins
module Debug
def who_am_i?
"#{self.class.name} (##{self.object_id}): #{self.to_s}"
end
end
class Foo
include Debug # 這個動作叫做 Mixin
# ...
end
class Bar
include Debug
# ...
end
ph = Foo.new("12312312")
et = Bar.new("78678678")
ph.who_am_i? # 輸出 "Foo (#330450): 12312312"
et.who_am_i? # 輸出 "Bar (#330420): 78678678"
61.
Module(2) Mixins
module Debug
def who_am_i?
"#{self.class.name} (##{self.object_id}): #{self.to_s}"
end
end
class Foo
include Debug # 這個動作叫做 Mixin
# ...
end
class Bar
include Debug
# ...
end
ph = Foo.new("12312312")
et = Bar.new("78678678")
ph.who_am_i? # 輸出 "Foo (#330450): 12312312"
et.who_am_i? # 輸出 "Bar (#330420): 78678678"
Ruby 使⽤用
Module 來解決
多重繼承問題
62.
⾛走訪迴圈
each method
languages = ['Ruby', 'Javascript', 'Perl']
languages.each do |lang|
puts 'I love ' + lang + '!'
end
# I Love Ruby
# I Love Javascript
# I Love Perl
63.
迭代器 iterator
• 不同於 while 迴圈⽤用法,each 是⼀一個陣
列的⽅方法,⾛走訪其中的元素,我們稱作
迭代器(iterator)
• 其中 do .... end 是 each ⽅方法的參數,稱
作匿名⽅方法( code block)
64.
最簡單的迭代器
3.times do
puts 'Good Job!'
end
# Good Job!
# Good Job!
# Good Job!
81.
Ruby Object Model
class A
end
class B < A
end
obj = B.new
obj.class # B
B.superclass # A
B.class # Class
obj B
Object
Class
A
class class
super
super
82.
class object is an object
of the class Class
obj B
Object
Class
A
class class
super
super
class
class
class
class A
end
class B < A
end
obj = B.new
obj.class # B
B.superclass # A
B.class # Class
83.
class A
end
module B
end
module C
end
class D < A
include B
include C
end
D.ancestors
=> [D, C, B, A, Object, Kernel, BasicObject]
module
obj D
A
Mixin
B,C
class
super
super
84.
class A
def foo
end
end
obj1 = A.new
obj2 = A.new
what’s metaclass?
obj2
Object
A
class
super
obj2
class
85.
obj2
Object
A
class
super
obj2’s
metaclass
obj2
class
super
class A
def foo
end
end
obj1 = A.new
obj2 = A.new
def obj2.bar
# only obj2 has bar method,
# called singleton method
end
# another way
class << obj1
def baz
#only obj1 has baz method
end
end
P.S. well, number and symbol have no metaclass
metaclassalso known as singleton, eigenclass, ghost class, virtual class.
every object has his own metaclass
86.
A
A’s
metaclass
super
Class
class
B
class
class A
# way1
def self.foo
end
# way2
class << self
def bar
end
end
end
# way3
def A.baz
end
A.foo
A.bar
A.baz
class object has its metaclass too.
so the singleton method is class
method!!
87.
動態型別 (duck typing)
會聒聒叫的就是鴨⼦子
# 鴨子
class Duck
def quack
puts "quack!"
end
end
# 野鴨 (不用繼承)
class Mallard
def quack
puts "qwuaacck!! quak!"
end
end
88.
Class 不是 Type
⼀一個物件可以做什麼才是重點
birds = [Duck.new, Mallard.new, Object.new]
# 迭代陣列,並呼叫方法 (無須擔心型別)
birds.each do |duck|
duck.quack if duck.respond_to? :quack
end
89.
Duck Typing(from wikipedia)
• duck typing is a style of dynamic typing in
which an object's methods and properties
determine the valid semantics, rather than
its inheritance from a particular class or
implementation of a specific interface
90.
prototype-based programming
Like JavaScript, Ruby can do, too
Animal = Object.new
def Animal.run
end
def Animal.sit
end
Cat = Animal.clone
Cat.run
Dog = Animal.clone
Dog.run
92.
“With Ruby, you can think in terms of
classes or in terms of objects.With
Javascript, you can think in terms of
prototypes or in terms of objects.With
Java and C++, classes are your only option.”
by Giles Bowkett
96.
pre- and Post-processing
usage example
f = File.open("myfile.txt", 'w')
f.write("Lorem ipsum dolor sit amet")
f.write("Lorem ipsum dolor sit amet")
f.close
# using block
File.open("myfile.txt", 'w') do |f|
f.write("Lorem ipsum dolor sit amet")
f.write("Lorem ipsum dolor sit amet")
end
97.
Dynamic Callbacks
Sinatra usage example
get '/posts' do
#.. show something ..
end
post '/posts' do
#.. create something ..
end
put '/posts/:id' do
#.. update something ..
end
delete '/posts/:id' do
#.. annihilate something ..
end
98.
Dynamic Callbacks
server = Server.new
server.handle(/hello/) do
puts "Hello at #{Time.now}"
end
server.handle(/goodbye/) do
puts "goodbye at #{Time.now}"
end
server.execute("/hello")
# Hello at Wed Apr 21 17:33:31 +0800 2010
server.execute("/goodbye")
# goodbye at Wed Apr 21 17:33:42 +0800 2010
99.
class Server
def initialize
@handlers = {}
end
def handle(pattern, &block)
@handlers[pattern] = block
end
def execute(url)
@handlers.each do |pattern, block|
if match = url.match(pattern)
block.call
break
end
end
end
end
100.
(2) Everything is an
expression
if found_dog == our_dog
name = found_dog.name
message = "We found our dog #{name}!"
else
message = "No luck"
end
101.
Everything is an
expression (cont.)
message = if found_dog == my_dog
name = found_dog.name
"We found our dog #{name}!"
else
"No luck"
end
107.
define_method
動態定義⽅方法
class Dragon
define_method(:foo) { puts "bar" }
['a','b','c','d','e','f'].each do |x|
define_method(x) { puts x }
end
end
dragon = Dragon.new
dragon.foo # 輸出 "bar"
dragon.a # 輸出 "a"
dragon.f # 輸出 "f"
108.
Rails example
class Firm < ActiveRecord::Base
has_many :clients
has_one :account
belongs_to :conglomorate
end
# has_many 是 AciveRecord 的 class method
# 其內容是動態定義出 Firm 的一堆 instance methods
firm = Firm.find(1)
firm.clients
firm.clients.size
firm.clients.build
firm.clients.destroy_all
109.
Memorize example
(Class Macro)
class Account
def calculate
@calculate ||= begin
sleep 10 # expensive calculation
5
end
end
end
a = Account.new
a.caculate # need waiting 10s to get 5
a.caculate # 5
a.caculate # 5
a.caculate # 5
110.
memoize method
class Account
def calculate
sleep 2 # expensive calculation
5
end
memoize :calculate
end
a = Account.new
a.calculate # need waiting 10s to get 5
a.calculate # 5
111.
class Class
def memoize(name)
original_method = "_original_#{name}"
alias_method :"#{original_method}", name
define_method name do
cache = instance_variable_get("@#{name}")
if cache
return cache
else
result = send(original_method) # Dynamic Dispatches
instance_variable_set("@#{name}", result)
return result
end
end
end
end
112.
It’s general for any class
class Car
def run
sleep 100 # expensive calculation
“done”
end
memoize :run
end
c = Car.new
c.run # need waiting 100s to get done
c.run # done
113.
Method Missing
car = Car.new
car.go_to_taipei
# go to taipei
car.go_to_shanghai
# go to shanghai
car.go_to_japan
# go to japan
114.
class Car
def go(place)
puts "go to #{place}"
end
def method_missing(name, *args)
if name.to_s =~ /^go_to_(.*)/
go($1)
else
super
end
end
end
car = Car.new
car.go_to_taipei
# go to taipei
car.blah # NoMethodError: undefined method `blah`
115.
XML builder example
builder = Builder::XmlMarkup.new(:target=>STDOUT, :indent=>2)
builder.person do |b|
b.name("Jim")
b.phone("555-1234")
b.address("Taipei, Taiwan")
end
# <person>
# <name>Jim</name>
# <phone>555-1234</phone>
# <address>Taipei, Taiwan</address>
# </person>
121.
All String are Encoded
• In Ruby 1.9 a String is a collection of
encoded characters.
除了 raw bytes,還包括 Encoding 資訊。
>> "中文".encoding.name
=> "UTF-8"
Encoding
object
122.
In Ruby 1.9, String has attached
Encoding object, and works in
characters.
124.
Transcoding fails
轉碼失敗
str = "Résumé"
str.encode("big5")
=> Encoding::UndefinedConversionError: "xC3xA9"
from UTF-8 to Big5
from (irb):2:in `encode'
from (irb):2
from /usr/local/bin/irb19:12:in `<main>'
125.
Force Transcoding
改變編碼,但不改 byte data
utf8 = "測試"
big5 = utf8.encode("big5")
big5.valid_encoding?
=> true
big5.force_encoding("utf-8")
big5.valid_encoding?
=> false
126.
Force Transcoding fails
編碼不對無法進⼀一步操作
big5.valid_encoding? # false
big5 =~ /123456/
=> ArgumentError: invalid byte sequence in UTF-8
from (irb):11
from /usr/local/bin/irb19:12:in `<main>'
127.
Encoding.compatible?
例如:ASCII with a bigger Encoding
ascii = "my ".force_encoding("ascii")
utf8 = "Résumé"
# 檢查相容性
Encoding.compatible?(ascii, utf8)
#<Encoding:UTF-8>
# 相加
my_resume = ascii + utf8
puts my_resume # "My Résumé"
puts my_resume.encoding.name # UTF-8
128.
Encoding.compatible?
不相容不能加在⼀一起
big5 = "測試".encode("big5")
utf8 = "Résumé"
# 檢查相容性
Encoding.compatible?(big5, utf8) # nil
# 相加
big5 + utf8
=> Encoding::CompatibilityError: incompatible character
encodings: Big5 and UTF-8
from (irb):25
from /usr/local/bin/irb19:12:in `<main>'
143.
What’s BDD?
• An improved xUnit Framework
• Focus on clearly describe the expected
behavior
• The emphasis is Tests as Documentation
rather than merely using tests for
verification.
145.
class OrderTest < Test::Unit::TestCase
def setup
@order = Order.new
end
def test_order_status_when_initialized
assert_equal @order.status, "New"
end
def test_order_amount_when_initialized
assert_equal @order.amount, 0
end
end
Test::Unit 寫法
146.
describe Order do
before do
@order = Order.new
end
context "when initialized" do
it "should have default status is New" do
@order.status.should == "New"
end
it "should have default amount is 0" do
@order.amount.should == 0
end
end
end
RSpec 寫法