Advertisement
Advertisement

More Related Content

Advertisement
Advertisement

Ruby 程式語言綜覽簡介

  1. Ruby 程式語⾔言 綜覽簡介 ihower@gmail.com 2013/4
  2. 我是誰? • 張⽂文鈿 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
  3. Agenda • 什麼是 Ruby • 基本語法 • Ruby 的幾個特點 • Ruby 的語⾔言實作 • 各式應⽤用 • ⽣生態圈
  4. 什麼是 Ruby? • 開放原碼、物件導向的動態直譯式 (interpreted)程式語⾔言 • 簡單哲學、⾼高⽣生產⼒力 • 精巧、⾃自然的語法 • 創造者 Yukihiro Matsumoto, a.k.a. Matz • 靈感來⾃自 Lisp, Perl, 和 Smalltalk • 設計的⺫⽬目的是要讓程式設計師 Happy
  5. Matz@RubyConf Taiwan 2012
  6. ⾺馬斯洛需求層次理論 ⽣生理 安全 社交 尊重 ⾃自我實現 Happy? DHH(Rails creator)
  7. http://redmonk.com/sogrady/2012/09/12/language-rankings-9-12/ Stackoverflow 和 Github 的熱⾨門排名
  8. irb: Interactive Ruby ⾺馬上動⼿手練習 irb(main):001:0> irb(main):001:0> 1 + 1 => 2 irb(main):002:0>
  9. PUTS 螢幕輸出 • 打開編輯器,編輯 hello.rb • 執⾏行 ruby hello.rb puts "Hello World!"
  10. 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++
  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:
  12. 1. Ruby 基本語法
  13. 整數 Integer 5 -205 9999999999 0
  14. 浮點數 Float 後⾯面有 . 54.321 0.001 -12.312 0.0
  15. 浮點數四則運算 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
  16. 整數四則運算 結果也會是整數 puts 1 + 2 puts 2 * 3 puts 5 - 8 puts 9 / 2 # 3 # 6 # -1 # 4
  17. 更多運算 puts 5 * (12-8) + -15 puts 98 + (59872 / (13*8)) * -52
  18. 字串 String puts 'Hello, world!' puts '' puts 'Good-bye.'
  19. 字串處理 puts 'I like ' + 'apple pie.' puts 'You're smart!' puts '12' + 12 #<TypeError: can't convert Fixnum into String>
  20. 更多字串⽅方法 var1 = 'stop' var2 = 'foobar' var3 = "aAbBcC" puts var1.reverse # 'pots' puts var2.length # 6 puts var3.upcase puts var3.downcase
  21. Ruby 完全地物件導向 每樣東⻄西都是物件,包括字串和數字。 # 輸出 "UPPER" puts "upper".upcase # 輸出 -5 的絕對值 puts -5.abs # 輸出 Fixnum puts 99.class # 輸出 "Ruby Rocks!" 五次 5.times do puts "Ruby Rocks!" end
  22. ⽅方法呼叫 Methods • 所有東⻄西都是物件(object),可以呼叫物 件的⽅方法,例如字串、整數、浮點數。 • 透過逗點 . 來對物件呼叫⽅方法
  23. 變數Variable ⼩小寫開頭,偏好單字之間以底線 _ 分隔 composer = 'Mozart' puts composer + ' was "da bomb", in his day.' my_composer = 'Beethoven' puts 'But I prefer ' + my_composer + ', personally.'
  24. 型別轉換 Conversions var1 = 2 var2 = '5' puts var1.to_s + var2 # 25 puts var1 + var2.to_i # 7 puts 9.to_f / 2 # 4.5
  25. 常數 Constant ⼤大寫開頭 foo = 1 foo = 2 Foo = 1 Foo = 2 # (irb):3: warning: already initialized constant Foo RUBY_PLATFORM ENV
  26. nil 表⽰示未設定值、未定義 nil # nil nil.class # NilClass nil.nil? # true 42.nil? # false nil == nil # true false == nil # false
  27. 註解 # 偏好均使⽤用單⾏行註解 # this is a comment line # this is a comment line =begin This is a comment line This is a comment line =end
  28. 陣列 Array a = [ 1, "cat", 3.14 ] puts a[0] # 輸出 1 puts a.size # 輸出 3 a[3] = nil puts a.inspect # 輸出字串 [1, "cat", nil]
  29. 更多陣列⽅方法 colors = ["red", "blue"] colors.push("black") colors << "white" puts colors.join(", ") # red, blue, black, white colors.pop puts colors.last #black
  30. 雜湊 Hash (Associative Array) config = { "foo" => 123, "bar" => 456 } puts config["foo"] # 輸出 123
  31. 字串符號 Symbols 唯⼀一且不會變動的識別名稱 config = { :foo => 123, :bar => 456 } puts config[:foo] # 輸出 123
  32. 流程控制 Flow Control
  33. ⽐比較⽅方法 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
  34. 控制結構 If if account.total > 100000 puts "large account" elsif account.total > 25000 puts "medium account" else puts "small account" end
  35. 控制結構 If if account.total > 100000 puts "large account" elsif account.total > 25000 puts "medium account" else puts "small account" end Perl Style
  36. 三元運算⼦子 expression ? true_expresion : false_expression x = 3 puts ( x > 3 )? "大於三" : "小於或等於三" # 輸出 小於或等於三
  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 可省 略,最後⼀一⾏行 就是回傳值
  44. ? 與 ! 的慣例 ⽅方法名稱可以⽤用?或!結尾,前者表⽰示會回傳 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]
  45. 類別 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
  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!
  65. code block ⼀一種匿名⽅方法,或稱作 closure { puts "Hello" } # 這是一個 block do puts "Blah" # 這也是一個 block puts "Blah" end
  66. 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 }
  67. 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 等迴圈
  68. 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]
  69. code block 當作判斷條件 # 迭代並根據條件刪除 a = [ "a", "b", "c" ] a.delete_if {|x| x >= "b" } # 結果是 ["a"] # 客製化排序 [2,1,3].sort! { |a, b| b <=> a } # 結果是 [3, 2, 1]
  70. 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
  71. code block 僅執⾏行⼀一次呼叫 file = File.new("testfile", "r") # ...處理檔案 file.close File.open("testfile", "r") do |file| # ...處理檔案 end # 檔案自動關閉
  72. 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"
  73. 帶參數的 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!"
  74. 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!"
  75. 傳遞不定參數 def my_sum(*val) val.inject(0) { |sum, v| sum + v } end puts my_sum(1,2,3,4) # 輸出 10
  76. 參數尾 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
  77. 例外處理 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
  78. 2. Ruby 的特點 Ruby supports multiple programming paradigms
  79. 1. Object-Oriented 物件導向程式設計
  80. Everything in Ruby is object, even class.
  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
  91. class-oriented programming v.s. object-oriented programming http://stackoverflow.com/questions/546670/what-is-the-difference-between-class- oriented-and-object-oriented-programming
  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
  93. 2. Functional Programming 函數式程式設計 http://www.slideshare.net/ihower/fp-osdc2012v2 https://github.com/JuanitoFatas/Ruby-Functional-Programming
  94. (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
  95. Higher-Order Functions (cont.) tickets = { "a" => 1100, "b" => 900, "c" => 800 } tickets.map{ |x| x[1] }.select{ |x| x < 1000 }.max # 900
  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
  102. (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]
  103. 3. Metaprogramming ⽤用程式寫程式 http://ihower.tw/blog/archives/4279
  104. Two types of meta- programming • Code Generation • eg. Rails scaffold • Reflection • eg. Class Macro
  105. 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
  106. Introspection (反射機制) # 這個物件有什麼方法 Object.methods => ["send", "name", "class_eval", "object_id", "new", "singleton_methods", ...] # 這個物件有這個方法嗎? Object.respond_to? :name => true
  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>
  116. DSL (Domain-Specific Language) • Internal DSL • 沿⽤用程式語⾔言本⾝身的 Syntax • Ruby 有⾮非常好的能⼒力可以作為 Internal DSL 之⽤用 • External DSL • ⾃自⾏行發明 Syntax,再⽤用程式語⾔言去解析
  117. 4. Encodings http://ihower.tw/blog/archives/2722
  118. UCS v.s. CSI • UCS (Universal Character Set) • 語⾔言內部統⼀一轉換成使⽤用 UTF-16 或 UTF-8,Java/Python/Perl 等⼤大部分語⾔言 都這樣做 • CSI (Character Set Independent) • Ruby 內建⽀支援 99 種 Encodings,並不 做轉換
  119. 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.
  120. 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"]
  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.
  123. 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]
  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>'
  129. 3. Ruby 的實作
  130. 程式語⾔言和程式語⾔言的實作, 是兩回事 (雖然很多語⾔言只有⼀一種實作) 程式語⾔言本⾝身沒有效能快慢,程式語⾔言的實作才有
  131. CRuby / MRI (Matz's Ruby Interpreter) • 1.8.7 is dead • 1.9.3 • 2.0 is released at 2/24/2013 (⼆二⼗十週年)
  132. JRuby
  133. Rubinius
  134. Concurrency models 的爭論 • process-based • CRuby has GVL (globalVM lock) • thread-based • reactor pattern • eventmachine (Ruby library) • node.js (JavaScript)
  135. IronRuby
  136. MacRuby
  137. RubyMotion
  138. mruby
  139. 4. Ruby 的應⽤用 how ruby change the world!
  140. Web framework • MVC • ORM • URL Routing • View Template
  141. Web Designer Tools • Sass/Less/Haml • Compass • Middleman
  142. Testing/BDDRuby community loves testing • RSpec • Cucumber http://ihower.tw/blog/archives/5438 http://ihower.tw/blog/archives/5983
  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.
  144. Terminology changed New paradigm: Executable Specification • “Test” becomes “Spec” • “Assertion” becomes “Expectation” • “test method” becomes “example” (RSpec) • “test case” becomes “example group” (RSpec)
  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 寫法
  147. DevOps • Chef • Puppet • Vagrant
  148. Mac
  149. Mac
  150. Blogging (static HTML generator)
  151. Redmine
  152. 5. Ruby ⽣生態圈
  153. 1. Editors & IDEs
  154. Vim for Rails
  155. Emacs for Rails
  156. 2.Web Services & Monitors
  157. 3.Hosting
  158. 3.a PaaS (Platform as a Service)
  159. 3.b ⾼高C/P值的VPS (Virtual Private Server)
  160. 3.b IaaS (Infrastructure as a service) Cloud Hosing
  161. 4. Consulting
  162. http://www.workingwithrails.com/
  163. 5. Conferences
  164. 6. Books
  165. http://www.pragprog.com/
  166. 閱讀練習時,⼩小⼼心 Rails 版本差異 1.2, 2.0, 2.1, 2.2, 2.3, 3.0, 3,1, 3.2 4.0 書籍尚未上市
  167. http://guides.rubyonrails.org/
  168. 7.Video
  169. http://peepcode.com/
  170. 8.Website & Blog (free)
  171. http://weblog.rubyonrails.org/
  172. http://www.rubyinside.com/
  173. http://ruby5.envylabs.com
  174. http://railscasts.com/
  175. http://www.rubyflow.com/
  176. http://github.com/
  177. 9. Ruby Community in Taiwan
  178. Ruby Tuesday 聚會
  179. ptt.cc #Ruby 版
  180. http://railsfun.tw/
  181. 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
  182. We’re hiring • Ruby on Rails developer • Front-end web developer • http://faria.co
Advertisement