Upgrade to Pro — share decks privately, control downloads, hide ads and more …

intro ruby

intro ruby

高达350页的介绍幻灯

Zoom.Quiet

May 06, 2013
Tweet

More Decks by Zoom.Quiet

Other Decks in Programming

Transcript

  1. 我是誰? • 張⽂文鈿 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
  2. Agenda • 什麼是 Ruby • 基本語法 • Ruby 的幾個特點 •

    Ruby 的語⾔言實作 • 各式應⽤用 • ⽣生態圈
  3. 什麼是 Ruby? • 開放原碼、物件導向的動態直譯式 (interpreted)程式語⾔言 • 簡單哲學、⾼高⽣生產⼒力 • 精巧、⾃自然的語法 •

    創造者 Yukihiro Matsumoto, a.k.a. Matz • 靈感來⾃自 Lisp, Perl, 和 Smalltalk • 設計的⺫⽬目的是要讓程式設計師 Happy
  4. 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++
  5. 什麼強?弱?分型 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:
  6. 浮點數四則運算 puts 1.0 + 2.0 puts 2.0 * 3.0 puts

    5.0 - 8.0 puts 9.0 / 2.0 # 3.0 # 6.0 # -3.0 # 4.5
  7. 字串處理 puts 'I like ' + 'apple pie.' puts 'You\'re

    smart!' puts '12' + 12 #<TypeError: can't convert Fixnum into String>
  8. 更多字串⽅方法 var1 = 'stop' var2 = 'foobar' var3 = "aAbBcC"

    puts var1.reverse # 'pots' puts var2.length # 6 puts var3.upcase puts var3.downcase
  9. Ruby 完全地物件導向 每樣東⻄西都是物件,包括字串和數字。 # 輸出 "UPPER" puts "upper".upcase # 輸出

    -5 的絕對值 puts -5.abs # 輸出 Fixnum puts 99.class # 輸出 "Ruby Rocks!" 五次 5.times do puts "Ruby Rocks!" end
  10. 變數 Variable ⼩小寫開頭,偏好單字之間以底線 _ 分隔 composer = 'Mozart' puts composer

    + ' was "da bomb", in his day.' my_composer = 'Beethoven' puts 'But I prefer ' + my_composer + ', personally.'
  11. 型別轉換 Conversions var1 = 2 var2 = '5' puts var1.to_s

    + var2 # 25 puts var1 + var2.to_i # 7 puts 9.to_f / 2 # 4.5
  12. 常數 Constant ⼤大寫開頭 foo = 1 foo = 2 Foo

    = 1 Foo = 2 # (irb):3: warning: already initialized constant Foo RUBY_PLATFORM ENV
  13. nil 表⽰示未設定值、未定義 nil # nil nil.class # NilClass nil.nil? #

    true 42.nil? # false nil == nil # true false == nil # false
  14. 註解 # 偏好均使⽤用單⾏行註解 # this is a comment line #

    this is a comment line =begin This is a comment line This is a comment line =end
  15. 陣列 Array a = [ 1, "cat", 3.14 ] puts

    a[0] # 輸出 1 puts a.size # 輸出 3 a[2] = nil puts a.inspect # 輸出 [1, "cat", nil]
  16. 更多陣列⽅方法 colors = ["red", "blue"] colors.push("black") colors << "white" puts

    colors.join(", ") # red, blue, black, white colors.pop puts colors.last #black
  17. 雜湊 Hash (Associative Array) config = { "foo" => 123,

    "bar" => 456 } puts config["foo"] # 輸出 123
  18. ⽐比較⽅方法 puts 1 > 2 puts 1 < 2 puts

    5 >= 5 puts 5 <= 4 puts 1 == 1 puts 2 != 1 puts ( 2 > 1 ) && ( 2 > 3 ) # and puts ( 2 > 1 ) || ( 2 > 3 ) # or
  19. 控制結構 If if account.total > 100000 puts "large account" elsif

    account.total > 25000 puts "medium account" else puts "small account" end
  20. 控制結構 If if account.total > 100000 puts "large account" elsif

    account.total > 25000 puts "medium account" else puts "small account" end Perl Style
  21. 三元運算⼦子 expression ? true_expresion : false_expression x = 3 puts

    ( x > 3 )? "大於三" : "小於或等於三" # 輸出 小於或等於三
  22. 控制結構 Case case name when "John" puts "Howdy John!" when

    "Ryan" puts "Whatz up Ryan!" else puts "Hi #{name}!" end
  23. 迴圈 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
  24. 真或假 只有 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
  25. Regular Expressions 與 Perl 接近的語法 # 抓出⼿手機號碼 phone = "123-456-7890"

    if phone =~ /(\d{3})-(\d{3})-(\d{4})/ ext = $1 city = $2 num = $3 end
  26. ⽅方法定義 Methods def 開頭 end 結尾 def say_hello(name) result =

    "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower
  27. ⽅方法定義 Methods def 開頭 end 結尾 def say_hello(name) result =

    "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower 字串相加
  28. ⽅方法定義 Methods def 開頭 end 結尾 def say_hello(name) result =

    "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower 字串相加 return 可省 略,最後⼀一⾏行 就是回傳值
  29. 類別 Classes ⼤大寫開頭,使⽤用 new 可以建⽴立出物件 color_string = String.new color_string =

    "" # 等同 color_array = Array.new color_array = [] # 等同 color_hash = Hash.new color_hash = {} # 等同 time = Time.new puts time
  30. 類別 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
  31. 類別 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 建構式
  32. 類別 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 建構式 物件變數
  33. 類別 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 建構式 物件變數 字串相加
  34. 類別 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 建構式 物件變數 字串相加 ⼤大寫開頭的 常數
  35. 類別 Class (續) class Person @@name = “ihower” def self.say

    puts @@name end end Person.say # 輸出 Hello, ihower
  36. 類別 Class (續) class Person @@name = “ihower” def self.say

    puts @@name end end Person.say # 輸出 Hello, ihower 類別變數
  37. 類別 Class (續) class Person @@name = “ihower” def self.say

    puts @@name end end Person.say # 輸出 Hello, ihower 類別變數 類別⽅方法
  38. 資料封裝 • 所有的物件變數(@開頭) 、類別變數(@@開頭) , 都是封裝在類別內部,類別外無法存取。 • 需透過定義 public ⽅方法才可以存取到

    class Person def initialize(name) @name = name end end p = Person.new('ihower') p.name => NoMethodError p.name='peny' => NoMethodError
  39. 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"
  40. ⽅方法封裝 預設是 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
  41. 類別 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 等同於
  42. 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"
  43. 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 來解決 多重繼承問題
  44. ⾛走訪迴圈 each method languages = ['Ruby', 'Javascript', 'Perl'] languages.each do

    |lang| puts 'I love ' + lang + '!' end # I Love Ruby # I Love Javascript # I Love Perl
  45. code block ⼀一種匿名⽅方法,或稱作 closure { puts "Hello" } # 這是一個

    block do puts "Blah" # 這也是一個 block puts "Blah" end
  46. code block 內部迭代器(iterator) # 處理陣列 people people = ["David", "John",

    "Mary"] people.each do |person| puts person end # 反覆五次 5.times { puts "Ruby rocks!" } # 從一數到九 1.upto(9) { |x| puts x }
  47. code block 內部迭代器(iterator) # 處理陣列 people people = ["David", "John",

    "Mary"] people.each do |person| puts person end # 反覆五次 5.times { puts "Ruby rocks!" } # 從一數到九 1.upto(9) { |x| puts x } 所以我們將 很少⽤用到 while, until, for 等迴圈
  48. 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]
  49. code block 當作判斷條件 # 迭代並根據條件刪除 a = [ "a", "b",

    "c" ] a.delete_if {|x| x >= "b" } # 結果是 ["a"] # 客製化排序 [2,1,3].sort! { |a, b| b <=> a } # 結果是 ["3",”2”,”1”]
  50. code block 有沒有 functional programming 的 fu? # 計算總和 (5..10).inject

    {|sum, n| sum + n } # 找出最長字串find the longest word longest = ["cat", "sheep", "bear"].inject do |memo, word| ( memo.length > word.length )? memo : word end
  51. code block 僅執⾏行⼀一次呼叫 file = File.new("testfile", "r") # ...處理檔案 file.close

    File.open("testfile", "r") do |file| # ...處理檔案 end # 檔案自動關閉
  52. 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"
  53. 帶參數的 code block def 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!"
  54. 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 object proc_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!"
  55. 參數尾 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
  56. 例外處理 raise, begin, rescue, ensure begin puts 10 / 0

    rescue => e puts e.class ensure # ... end # 輸出 ZeroDivisionError raise "Not works!!" # 丟出一個 RuntimeError # 自行自定例外物件 class MyException < RuntimeError end raise MyException
  57. 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
  58. 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
  59. 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
  60. class A def foo end end obj1 = A.new obj2

    = A.new what’s metaclass? obj2 Object A class super obj2 class
  61. 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 metaclass also known as singleton, eigenclass, ghost class, virtual class. every object has his own metaclass
  62. 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!!
  63. 動態型別 (duck typing) 會聒聒叫的就是鴨⼦子 # 鴨子 class Duck def quack

    puts "quack!" end end # 野鴨 (不用繼承) class Mallard def quack puts "qwuaacck!! quak!" end end
  64. Class 不是 Type ⼀一個物件可以做什麼才是重點 birds = [Duck.new, Mallard.new, Object.new] #

    迭代陣列,並呼叫方法 (無須擔心型別) birds.each do |duck| duck.quack if duck.respond_to? :quack end
  65. 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
  66. 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
  67. “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
  68. (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 end end highest_price # 900
  69. Higher-Order Functions (cont.) tickets = { "a" => 1100, "b"

    => 900, "c" => 800 } tickets.map{ |x| x[1] }.select{ |x| x < 1000 }.max # 900
  70. 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
  71. 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
  72. 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
  73. 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
  74. (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
  75. Everything is an expression (cont.) message = if found_dog ==

    my_dog name = found_dog.name "We found our dog #{name}!" else "No luck" end
  76. (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]
  77. Two types of meta- programming • Code Generation • eg.

    Rails scaffold • Reflection • eg. Class Macro
  78. 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
  79. Introspection (反射機制) # 這個物件有什麼方法 Object.methods => ["send", "name", "class_eval", "object_id",

    "new", "singleton_methods", ...] # 這個物件有這個方法嗎? Object.respond_to? :name => true
  80. 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"
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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`
  88. 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>
  89. DSL (Domain-Specific Language) • Internal DSL • 沿⽤用程式語⾔言本⾝身的 Syntax •

    Ruby 有⾮非常好的能⼒力可以作為 Internal DSL 之⽤用 • External DSL • ⾃自⾏行發明 Syntax,再⽤用程式語⾔言去解析
  90. UCS v.s. CSI • UCS (Universal Character Set) • 語⾔言內部統⼀一轉換成使⽤用

    UTF-16 或 UTF-8,Java/Python/Perl 等⼤大部分語⾔言 都這樣做 • CSI (Character Set Independent) • Ruby 內建⽀支援 99 種 Encodings,並不 做轉換
  91. 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.
  92. 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"]
  93. 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
  94. Transcoding 改變編碼 utf8 = "測試" utf8.bytesize # 6 utf8.bytes.to_a #

    [230, 184, 172, 232, 169, 166] big5 = utf8.encode("big5") big5.encoding.name # ”Big5” big5.bytesize # 4 big5.bytes.to_a # [180, 250, 184, 213]
  95. 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>'
  96. Force Transcoding 改變編碼,但不改 byte data utf8 = "測試" big5 =

    utf8.encode("big5") big5.valid_encoding? => true big5.force_encoding("utf-8") big5.valid_encoding? => false
  97. 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>'
  98. 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
  99. 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>'
  100. CRuby / MRI (Matz's Ruby Interpreter) • 1.8.7 is dead

    • 1.9.3 • 2.0 is released at 2/24/2013 (⼆二⼗十週年)
  101. Concurrency models 的爭論 • process-based • CRuby has GVL (global

    VM lock) • thread-based • reactor pattern • eventmachine (Ruby library) • node.js (JavaScript)
  102. 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.
  103. Terminology changed New paradigm: Executable Specification • “Test” becomes “Spec”

    • “Assertion” becomes “Expectation” • “test method” becomes “example” (RSpec) • “test case” becomes “example group” (RSpec)
  104. 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 寫法
  105. 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 寫法
  106. Mac

  107. Mac

  108. 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/ecosystem http://infoether.com/ruby-and-rails-whitepaper