View
56
Download
14
Tags:
Embed Size (px)
DESCRIPTION
Citation preview
我是誰?• 張⽂文鈿 a.k.a. ihower
• http://ihower.tw
• http://twitter.com/ihower
• Ruby Developer since 2006
• CTO, Faria Systems Ltd.
• The organizer of RubyConf Taiwan
• http://rubyconf.tw
• http://ruby.tw
Agenda
• 什麼是 Ruby
• 基本語法• Ruby 的幾個特點
• Ruby 的語⾔言實作
• 各式應⽤用• ⽣生態圈
什麼是 Ruby?
• 開放原碼、物件導向的動態直譯式(interpreted)程式語⾔言
• 簡單哲學、⾼高⽣生產⼒力• 精巧、⾃自然的語法• 創造者 Yukihiro Matsumoto, a.k.a. Matz
• 靈感來⾃自 Lisp, Perl, 和 Smalltalk
• 設計的⺫⽬目的是要讓程式設計師 Happy
Matz@RubyConf Taiwan 2012
⾺馬斯洛需求層次理論
⽣生理
安全
社交
尊重
⾃自我實現
Happy?
DHH(Rails creator)
http://redmonk.com/sogrady/2012/09/12/language-rankings-9-12/
Stackoverflow 和Github 的熱⾨門排名
irb: Interactive Ruby⾺馬上動⼿手練習
irb(main):001:0>
irb(main):001:0> 1 + 1=> 2
irb(main):002:0>
PUTS 螢幕輸出
• 打開編輯器,編輯 hello.rb
• 執⾏行 ruby hello.rb
puts "Hello World!"
Ruby 是動態強分型語⾔言
• 動態 Dynamic v.s. 靜態 Static typing
• Ruby/Perl/Python/PHP v.s. Java/C/C++
• 強 Strong v.s. 弱 Weak typing
• Ruby/Perl/Python/Java v.s. PHP/C/C++
什麼強?弱?分型
i=1puts "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:
1. Ruby 基本語法
整數 Integer
5-20599999999990
浮點數 Float後⾯面有 .
54.3210.001-12.3120.0
浮點數四則運算puts 1.0 + 2.0puts 2.0 * 3.0puts 5.0 - 8.0puts 9.0 / 2.0
# 3.0# 6.0# -3.0# 4.5
整數四則運算結果也會是整數
puts 1 + 2puts 2 * 3puts 5 - 8puts 9 / 2
# 3# 6# -1# 4
更多運算
puts 5 * (12-8) + -15puts 98 + (59872 / (13*8)) * -52
字串 String
puts 'Hello, world!'puts ''puts 'Good-bye.'
字串處理puts 'I like ' + 'apple pie.'puts 'You\'re smart!'
puts '12' + 12 #<TypeError: can't convert Fixnum into String>
更多字串⽅方法var1 = 'stop'var2 = 'foobar'var3 = "aAbBcC"
puts var1.reverse # 'pots'puts var2.length # 6puts var3.upcaseputs var3.downcase
Ruby 完全地物件導向每樣東⻄西都是物件,包括字串和數字。
# 輸出 "UPPER"puts "upper".upcase # 輸出 -5 的絕對值puts -5.abs
# 輸出 Fixnumputs 99.class # 輸出 "Ruby Rocks!" 五次5.times do puts "Ruby Rocks!"end
⽅方法呼叫 Methods
• 所有東⻄西都是物件(object),可以呼叫物件的⽅方法,例如字串、整數、浮點數。
• 透過逗點 . 來對物件呼叫⽅方法
變數 Variable⼩小寫開頭,偏好單字之間以底線 _ 分隔
composer = 'Mozart'puts composer + ' was "da bomb", in his day.'
my_composer = 'Beethoven'puts 'But I prefer ' + my_composer + ', personally.'
型別轉換 Conversions
var1 = 2var2 = '5'
puts var1.to_s + var2 # 25puts var1 + var2.to_i # 7
puts 9.to_f / 2 # 4.5
常數 Constant⼤大寫開頭
foo = 1foo = 2
Foo = 1Foo = 2 # (irb):3: warning: already initialized constant Foo
RUBY_PLATFORMENV
nil表⽰示未設定值、未定義
nil # nilnil.class # NilClass
nil.nil? # true42.nil? # false
nil == nil # truefalse == nil # false
註解 #偏好均使⽤用單⾏行註解
# this is a comment line# this is a comment line
=begin This is a comment line This is a comment line=end
陣列 Arraya = [ 1, "cat", 3.14 ]
puts a[0] # 輸出 1puts a.size # 輸出 3
a[3] = nilputs a.inspect # 輸出字串 [1, "cat", nil]
更多陣列⽅方法colors = ["red", "blue"]
colors.push("black")colors << "white"puts colors.join(", ") # red, blue, black, white
colors.popputs colors.last #black
雜湊 Hash(Associative Array)
config = { "foo" => 123, "bar" => 456 }
puts config["foo"] # 輸出 123
字串符號 Symbols唯⼀一且不會變動的識別名稱
config = { :foo => 123, :bar => 456 }
puts config[:foo] # 輸出 123
流程控制 Flow Control
⽐比較⽅方法puts 1 > 2puts 1 < 2puts 5 >= 5puts 5 <= 4puts 1 == 1puts 2 != 1
puts ( 2 > 1 ) && ( 2 > 3 ) # andputs ( 2 > 1 ) || ( 2 > 3 ) # or
控制結構 If
if account.total > 100000 puts "large account"elsif account.total > 25000 puts "medium account"else puts "small account"end
控制結構 If
if account.total > 100000 puts "large account"elsif account.total > 25000 puts "medium account"else puts "small account"end
Perl Style
三元運算⼦子expression ? true_expresion : false_expression
x = 3puts ( x > 3 )? "大於三" : "小於或等於三"
# 輸出 小於或等於三
控制結構 Case
case name when "John" puts "Howdy John!" when "Ryan" puts "Whatz up Ryan!" else puts "Hi #{name}!"end
迴圈while, loop, until, next and break
i = 0loop do i += 1 break if i > 10 # 中斷迴圈
end
i=0while ( i < 10 ) i += 1 next if i % 2 == 0 #跳過雙數
end
i = 0i += 1 until i > 10puts i# 輸出 11
真或假只有 false 和 nil 是假,其他為真
puts "not execute" if nilputs "not execute" if false
puts "execute" if true # 輸出 executeputs "execute" if “” # 輸出 execute (和JavaScript不同)puts "execute" if 0 # 輸出 execute (和C不同)puts "execute" if 1 # 輸出 executeputs "execute" if "foo" # 輸出 executeputs "execute" if Array.new # 輸出 execute
Regular Expressions與 Perl 接近的語法
# 抓出⼿手機號碼 phone = "123-456-7890" if phone =~ /(\d{3})-(\d{3})-(\d{4})/ ext = $1 city = $2 num = $3end
⽅方法定義 Methodsdef 開頭 end 結尾
def say_hello(name) result = "Hi, " + name return resultend
puts say_hello('ihower')# 輸出 Hi, ihower
⽅方法定義 Methodsdef 開頭 end 結尾
def say_hello(name) result = "Hi, " + name return resultend
puts say_hello('ihower')# 輸出 Hi, ihower
字串相加
⽅方法定義 Methodsdef 開頭 end 結尾
def say_hello(name) result = "Hi, " + name return resultend
puts say_hello('ihower')# 輸出 Hi, ihower
字串相加
return 可省略,最後⼀一⾏行就是回傳值
? 與 ! 的慣例⽅方法名稱可以⽤用?或!結尾,前者表⽰示會回傳 Boolean,
後者暗⽰示會有某種 side-effect。
array=[2,1,3]
array.empty? # false
array.sort # [1,2,3]array.inspect # [2,1,3]
array.sort! # [1,2,3]array.inspect # [1,2,3]
類別 Classes⼤大寫開頭,使⽤用 new 可以建⽴立出物件
color_string = String.new color_string = "" # 等同
color_array = Array.newcolor_array = [] # 等同
color_hash = Hash.newcolor_hash = {} # 等同
time = Time.newputs time
類別 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, ihowerp2.say("Hello") # 輸出 Hello, ihover
類別 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, ihowerp2.say("Hello") # 輸出 Hello, ihover
建構式
類別 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, ihowerp2.say("Hello") # 輸出 Hello, ihover
建構式
物件變數
類別 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, ihowerp2.say("Hello") # 輸出 Hello, ihover
建構式
物件變數
字串相加
類別 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, ihowerp2.say("Hello") # 輸出 Hello, ihover
建構式
物件變數
字串相加
⼤大寫開頭的常數
類別 Class (續)
class Person
@@name = “ihower” def self.say puts @@name end end
Person.say # 輸出 Hello, ihower
類別 Class (續)
class Person
@@name = “ihower” def self.say puts @@name end end
Person.say # 輸出 Hello, ihower
類別變數
類別 Class (續)
class Person
@@name = “ihower” def self.say puts @@name end end
Person.say # 輸出 Hello, ihower
類別變數
類別⽅方法
資料封裝• 所有的物件變數(@開頭)、類別變數(@@開頭),都是封裝在類別內部,類別外無法存取。
• 需透過定義 public ⽅方法才可以存取到class Person def initialize(name) @name = name endend
p = Person.new('ihower')p.name => NoMethodErrorp.name='peny' => NoMethodError
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"
⽅方法封裝預設是 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
類別 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
等同於
Class 繼承class Pet attr_accessor :name, :ageend
class Cat < Petend
class Dog < Petend
Module (1) Namespacemodule MyUtil
def self.foobar puts "foobar" end end
MyUtil.foobar# 輸出 foobar
Module(2) Mixinsmodule Debug def who_am_i? "#{self.class.name} (\##{self.object_id}): #{self.to_s}" endend
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"
Module(2) Mixinsmodule Debug def who_am_i? "#{self.class.name} (\##{self.object_id}): #{self.to_s}" endend
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 來解決多重繼承問題
⾛走訪迴圈 each method
languages = ['Ruby', 'Javascript', 'Perl']
languages.each do |lang| puts 'I love ' + lang + '!'end
# I Love Ruby# I Love Javascript# I Love Perl
迭代器 iterator
• 不同於 while 迴圈⽤用法,each 是⼀一個陣列的⽅方法,⾛走訪其中的元素,我們稱作迭代器(iterator)
• 其中 do .... end 是 each ⽅方法的參數,稱作匿名⽅方法( code block)
最簡單的迭代器3.times do puts 'Good Job!'end
# Good Job!# Good Job!# Good Job!
code block⼀一種匿名⽅方法,或稱作 closure
{ puts "Hello" } # 這是一個 block
do puts "Blah" # 這也是一個 block puts "Blah"end
code block內部迭代器(iterator)
# 處理陣列 people
people = ["David", "John", "Mary"]people.each do |person| puts personend # 反覆五次
5.times { puts "Ruby rocks!" }
# 從一數到九
1.upto(9) { |x| puts x }
code block內部迭代器(iterator)
# 處理陣列 people
people = ["David", "John", "Mary"]people.each do |person| puts personend # 反覆五次
5.times { puts "Ruby rocks!" }
# 從一數到九
1.upto(9) { |x| puts x }
所以我們將很少⽤用到
while, until, for 等迴圈
code block其他迭代⽅方式
# 迭代並造出另一個陣列
a = [ "a", "b", "c", "d" ]b = a.map {|x| x + "!" }puts b.inspect# 結果是 ["a!", "b!", "c!", "d!"]
# 找出符合條件的值
b = [1,2,3].find_all{ |x| x % 2 == 0 }b.inspect# 結果是 [2]
code block當作判斷條件
# 迭代並根據條件刪除
a = [ "a", "b", "c" ]a.delete_if {|x| x >= "b" }# 結果是 ["a"]
# 客製化排序
[2,1,3].sort! { |a, b| b <=> a }# 結果是 [3, 2, 1]
code block有沒有 functional programming 的 fu?
# 計算總和
(5..10).inject {|sum, n| sum + n }
# 找出最長字串find the longest wordlongest = ["cat", "sheep", "bear"].inject do |memo, word| ( memo.length > word.length )? memo : wordend
code block僅執⾏行⼀一次呼叫
file = File.new("testfile", "r")# ...處理檔案
file.close
File.open("testfile", "r") do |file| # ...處理檔案
end# 檔案自動關閉
Yield在⽅方法中使⽤用 yield 來執⾏行 code block
# 定義方法
def call_block puts "Start" yield yield puts "End"end call_block { puts "Blocks are cool!" }# 輸出 # "Start" # "Blocks are cool!" # "Blocks are cool!" # "End"
帶參數的 code blockdef call_block yield(1) yield(2) yield(3)end call_block { |i| puts "#{i}: Blocks are cool!"}# 輸出 # "1: Blocks are cool!" # "2: Blocks are cool!"# "3: Blocks are cool!"
Proc object將 code block 明確轉成物件
def call_block(&block) block.call(1) block.call(2) block.call(3)end call_block { |i| puts "#{i}: Blocks are cool!" }
# 或是先宣告出 proc objectproc_1 = Proc.new { |i| puts "#{i}: Blocks are cool!" }proc_2 = lambda { |i| puts "#{i}: Blocks are cool!" }
call_block(&proc_1)call_block(&proc_2)
# 輸出 # "1: Blocks are cool!" # "2: Blocks are cool!"# "3: Blocks are cool!"
傳遞不定參數def my_sum(*val) val.inject(0) { |sum, v| sum + v }end
puts my_sum(1,2,3,4)
# 輸出 10
參數尾 Hash 可省略 { } def my_print(a, b, options) puts a puts b puts options[:x] puts options[:y] puts options[:z]end
my_print("A", "B", { :x => 123, :z => 456 } ) my_print("A", "B", :x => 123, :z => 456) # 結果相同
# 輸出 A# 輸出 B# 輸出 123# 輸出 nil# 輸出 456
例外處理raise, begin, rescue, ensure
begin puts 10 / 0rescue => e puts e.classensure # ...end
# 輸出 ZeroDivisionError
raise "Not works!!"# 丟出一個 RuntimeError
# 自行自定例外物件
class MyException < RuntimeError end
raise MyException
2. Ruby 的特點Ruby supports multiple programming paradigms
1. Object-Oriented物件導向程式設計
Everything in Ruby is object, even class.
Ruby Object Model
class Aend
class B < Aend
obj = B.new
obj.class # B B.superclass # AB.class # Class obj B
Object
Class
A
class class
super
super
class object is an object of the class Class
obj B
Object
Class
A
class class
super
super
class
class
class
class Aend
class B < Aend
obj = B.new
obj.class # B B.superclass # AB.class # Class
class Aend
module Bend
module Cend
class D < A include B include Cend
D.ancestors=> [D, C, B, A, Object, Kernel, BasicObject]
module
obj D
A
MixinB,C
class
super
super
class A def foo endend
obj1 = A.newobj2 = A.new
what’s metaclass?
obj2
Object
A
class
super
obj2class
obj2
Object
A
class
super
obj2’s metaclass
obj2class
super
class A def foo endend
obj1 = A.newobj2 = A.new
def obj2.bar # only obj2 has bar method, # called singleton methodend
# another wayclass << obj1 def baz #only obj1 has baz method endend
P.S. well, number and symbol have no metaclass
metaclass also known as singleton, eigenclass, ghost class, virtual class.
every object has his own metaclass
AA’s
metaclass
super
Classclass
B
class
class A # way1 def self.foo end # way2 class << self def bar end end end
# way3def A.bazend
A.fooA.barA.baz
class object has its metaclass too. so the singleton method is class
method!!
動態型別 (duck typing)會聒聒叫的就是鴨⼦子
# 鴨子
class Duck def quack puts "quack!" endend # 野鴨 (不用繼承)class Mallard def quack puts "qwuaacck!! quak!" endend
Class 不是 Type⼀一個物件可以做什麼才是重點
birds = [Duck.new, Mallard.new, Object.new]
# 迭代陣列,並呼叫方法 (無須擔心型別)
birds.each do |duck| duck.quack if duck.respond_to? :quackend
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
prototype-based programmingLike JavaScript, Ruby can do, too
Animal = Object.new
def Animal.runend
def Animal.sitend
Cat = Animal.cloneCat.run
Dog = Animal.cloneDog.run
class-oriented programmingv.s.
object-oriented programming
http://stackoverflow.com/questions/546670/what-is-the-difference-between-class-oriented-and-object-oriented-programming
“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
2. Functional Programming函數式程式設計
http://www.slideshare.net/ihower/fp-osdc2012v2
https://github.com/JuanitoFatas/Ruby-Functional-Programming
(1) Higher-Order Functions
tickets = { "a" => 1100, "b" => 900, "c" => 800 }
highest_price = 0
tickets.each do |ticket, price| if price < 1000 highest_price = price if price > highest_price endend
highest_price # 900
Higher-Order Functions(cont.)
tickets = { "a" => 1100, "b" => 900, "c" => 800 }
tickets.map{ |x| x[1] }.select{ |x| x < 1000 }.max # 900
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 blockFile.open("myfile.txt", 'w') do |f| f.write("Lorem ipsum dolor sit amet") f.write("Lorem ipsum dolor sit amet") end
Dynamic CallbacksSinatra 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
Dynamic Callbacksserver = 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 2010server.execute("/goodbye") # goodbye at Wed Apr 21 17:33:42 +0800 2010
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
(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
Everything is an expression (cont.)
message = if found_dog == my_dog name = found_dog.name "We found our dog #{name}!"else "No luck"end
(3) Lazy enumerators
require 'prime'
Prime.to_a # 這樣是無窮數列...
Prime.take(10).to_a# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Prime.lazy.select{ |x| x % 4 == 3 }.take(10).to_a# => [3, 7, 11, 19, 23, 31, 43, 47, 59, 67]
3. Metaprogramming⽤用程式寫程式
http://ihower.tw/blog/archives/4279
Two types of meta-programming
• Code Generation
• eg. Rails scaffold
• Reflection
• eg. Class Macro
Class Bodies Aren’t Special
class Demo a = 1 puts a
def self.say puts "blah" end say # you can execute class method in class body end
# 1# blah
Introspection (反射機制)
# 這個物件有什麼方法
Object.methods=> ["send", "name", "class_eval", "object_id", "new", "singleton_methods", ...] # 這個物件有這個方法嗎?
Object.respond_to? :name=> true
define_method動態定義⽅方法
class Dragon define_method(:foo) { puts "bar" }
['a','b','c','d','e','f'].each do |x| define_method(x) { puts x } endend
dragon = Dragon.newdragon.foo # 輸出 "bar"dragon.a # 輸出 "a"dragon.f # 輸出 "f"
Rails exampleclass Firm < ActiveRecord::Base has_many :clients has_one :account belongs_to :conglomorateend
# has_many 是 AciveRecord 的 class method# 其內容是動態定義出 Firm 的一堆 instance methods
firm = Firm.find(1)firm.clientsfirm.clients.sizefirm.clients.buildfirm.clients.destroy_all
Memorize example(Class Macro)
class Account
def calculate @calculate ||= begin sleep 10 # expensive calculation 5 end end end
a = Account.newa.caculate # need waiting 10s to get 5a.caculate # 5a.caculate # 5a.caculate # 5
memoize methodclass Account def calculate sleep 2 # expensive calculation 5 end
memoize :calculate end
a = Account.newa.calculate # need waiting 10s to get 5a.calculate # 5
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 endend
It’s general for any classclass Car def run sleep 100 # expensive calculation “done” end
memoize :run end
c = Car.newc.run # need waiting 100s to get donec.run # done
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
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 endend
car = Car.new
car.go_to_taipei# go to taipei
car.blah # NoMethodError: undefined method `blah`
XML builder examplebuilder = 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>
DSL(Domain-Specific Language)
• Internal DSL
• 沿⽤用程式語⾔言本⾝身的 Syntax
• Ruby 有⾮非常好的能⼒力可以作為 Internal DSL 之⽤用
• External DSL
• ⾃自⾏行發明 Syntax,再⽤用程式語⾔言去解析
4. Encodings
http://ihower.tw/blog/archives/2722
UCS v.s. CSI
• UCS (Universal Character Set)
• 語⾔言內部統⼀一轉換成使⽤用 UTF-16 或 UTF-8,Java/Python/Perl 等⼤大部分語⾔言都這樣做
• CSI (Character Set Independent)
• Ruby 內建⽀支援 99 種 Encodings,並不做轉換
pick one encoding, likely Unicode, and works all data in one format? No.
Ruby 1.9 make it possible to work with data with 99 encoding.
1.9.3-p392 :024 > Encoding.name_list => ["ASCII-8BIT", "UTF-8", "US-ASCII", "Big5", "Big5-HKSCS", "Big5-UAO", "CP949", "Emacs-Mule", "EUC-JP", "EUC-KR", "EUC-TW", "GB18030", "GBK", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "KOI8-R", "KOI8-U", "Shift_JIS", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "Windows-1251", "BINARY", "IBM437", "CP437", "IBM737", "CP737", "IBM775", "CP775", "CP850", "IBM850", "IBM852", "CP852", "IBM855", "CP855", "IBM857", "CP857", "IBM860", "CP860", "IBM861", "CP861", "IBM862", "CP862", "IBM863", "CP863", "IBM864", "CP864", "IBM865", "CP865", "IBM866", "CP866", "IBM869", "CP869", "Windows-1258", "CP1258", "GB1988", "macCentEuro", "macCroatian", "macCyrillic", "macGreek", "macIceland", "macRoman", "macRomania", "macThai", "macTurkish", "macUkraine", "CP950", "Big5-HKSCS:2008", "CP951", "stateless-ISO-2022-JP", "eucJP", "eucJP-ms", "euc-jp-ms", "CP51932", "eucKR", "eucTW", "GB2312", "EUC-CN", "eucCN", "GB12345", "CP936", "ISO-2022-JP", "ISO2022-JP", "ISO-2022-JP-2", "ISO2022-JP2", "CP50220", "CP50221", "ISO8859-1", "Windows-1252", "CP1252", "ISO8859-2", "Windows-1250", "CP1250", "ISO8859-3", "ISO8859-4", "ISO8859-5", "ISO8859-6", "Windows-1256", "CP1256", "ISO8859-7", "Windows-1253", "CP1253", "ISO8859-8", "Windows-1255", "CP1255", "ISO8859-9", "Windows-1254", "CP1254", "ISO8859-10", "ISO8859-11", "TIS-620", "Windows-874", "CP874", "ISO8859-13", "Windows-1257", "CP1257", "ISO8859-14", "ISO8859-15", "ISO8859-16", "CP878", "Windows-31J", "CP932", "csWindows31J", "SJIS", "PCK", "MacJapanese", "MacJapan", "ASCII", "ANSI_X3.4-1968", "646", "UTF-7", "CP65000", "CP65001", "UTF8-MAC", "UTF-8-MAC", "UTF-8-HFS", "UTF-16", "UTF-32", "UCS-2BE", "UCS-4BE", "UCS-4LE", "CP1251", "UTF8-DoCoMo", "SJIS-DoCoMo", "UTF8-KDDI", "SJIS-KDDI", "ISO-2022-JP-KDDI", "stateless-ISO-2022-JP-KDDI", "UTF8-SoftBank", "SJIS-SoftBank", "locale", "external", "filesystem", "internal"]
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
In Ruby 1.9, String has attached Encoding object, and works in
characters.
Transcoding改變編碼
utf8 = "測試"utf8.bytesize # 6utf8.bytes.to_a # [230, 184, 172, 232, 169, 166]
big5 = utf8.encode("big5")
big5.encoding.name # ”Big5”big5.bytesize # 4big5.bytes.to_a # [180, 250, 184, 213]
Transcoding fails轉碼失敗
str = "Résumé"str.encode("big5")
=> Encoding::UndefinedConversionError: "\xC3\xA9" from UTF-8 to Big5 from (irb):2:in `encode' from (irb):2 from /usr/local/bin/irb19:12:in `<main>'
Force Transcoding改變編碼,但不改 byte data
utf8 = "測試"
big5 = utf8.encode("big5")big5.valid_encoding?=> true
big5.force_encoding("utf-8")big5.valid_encoding?=> false
Force Transcoding fails編碼不對無法進⼀一步操作
big5.valid_encoding? # falsebig5 =~ /123456/
=> ArgumentError: invalid byte sequence in UTF-8 from (irb):11 from /usr/local/bin/irb19:12:in `<main>'
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 + utf8puts my_resume # "My Résumé"puts my_resume.encoding.name # UTF-8
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>'
3. Ruby 的實作
程式語⾔言和程式語⾔言的實作,是兩回事
(雖然很多語⾔言只有⼀一種實作)程式語⾔言本⾝身沒有效能快慢,程式語⾔言的實作才有
CRuby / MRI (Matz's Ruby Interpreter)
• 1.8.7 is dead
• 1.9.3
• 2.0 is released at 2/24/2013 (⼆二⼗十週年)
JRuby
Rubinius
Concurrency models 的爭論
• process-based
• CRuby has GVL (global VM lock)
• thread-based
• reactor pattern
• eventmachine (Ruby library)
• node.js (JavaScript)
IronRuby
MacRuby
RubyMotion
mruby
4. Ruby 的應⽤用how ruby change the world!
Web framework
• MVC
• ORM
• URL Routing
• View Template
Web Designer Tools• Sass/Less/Haml
• Compass
• Middleman
Testing/BDDRuby community loves testing
• RSpec
• Cucumber
http://ihower.tw/blog/archives/5438
http://ihower.tw/blog/archives/5983
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.
Terminology changedNew paradigm: Executable Specification
• “Test” becomes “Spec”
• “Assertion” becomes “Expectation”
• “test method” becomes “example” (RSpec)
• “test case” becomes “example group” (RSpec)
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 寫法
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 endend
RSpec 寫法
DevOps
• Chef
• Puppet
• Vagrant
Mac
Mac
Blogging(static HTML generator)
Redmine
5. Ruby ⽣生態圈
1. Editors & IDEs
Vim for Rails
Emacs for Rails
2. Web Services & Monitors
3.Hosting
3.aPaaS (Platform as a Service)
3.b ⾼高C/P值的 VPS (Virtual Private Server)
3.b IaaS (Infrastructure as a service)
Cloud Hosing
4. Consulting
5. Conferences
6. Books
閱讀練習時,⼩小⼼心 Rails 版本差異1.2, 2.0, 2.1, 2.2, 2.3, 3.0, 3,1, 3.2
4.0 書籍尚未上市
7. Video
8. Website & Blog(free)
9. Ruby Communityin Taiwan
Ruby Tuesday 聚會
ptt.cc #Ruby 版
Thank you.
參考資料:Beginning Ruby 2nd. (Apress)Programming Ruby (The Pragmatic Programmers)The Well-Grounded Rubyist (Manning)Ruby 程式設計 (O’Reilly)Foundation Rails 2 (friendsof)http://rubyonrails.org/ecosystemhttp://infoether.com/ruby-and-rails-whitepaper
We’re hiring
• Ruby on Rails developer
• Front-end web developer
• http://faria.co