• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Ruby 程式語言綜覽簡介
 

Ruby 程式語言綜覽簡介

on

  • 7,565 views

 

Statistics

Views

Total Views
7,565
Views on SlideShare
7,467
Embed Views
98

Actions

Likes
59
Downloads
326
Comments
1

2 Embeds 98

http://www.plurk.com 78
http://aws.w3db.us 20

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Ruby 程式語言綜覽簡介 Ruby 程式語言綜覽簡介 Presentation Transcript

    • Ruby 程式語⾔言 綜覽簡介 ihower@gmail.com 2013/4
    • 我是誰? • 張⽂文鈿 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=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:
    • 1. Ruby 基本語法
    • 整數 Integer 5 -205 9999999999 0
    • 浮點數 Float 後⾯面有 . 54.321 0.001 -12.312 0.0
    • 浮點數四則運算 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
    • 整數四則運算 結果也會是整數 puts 1 + 2 puts 2 * 3 puts 5 - 8 puts 9 / 2 # 3 # 6 # -1 # 4
    • 更多運算 puts 5 * (12-8) + -15 puts 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 # 6 puts var3.upcase puts var3.downcase
    • Ruby 完全地物件導向 每樣東⻄西都是物件,包括字串和數字。 # 輸出 "UPPER" puts "upper".upcase # 輸出 -5 的絕對值 puts -5.abs # 輸出 Fixnum puts 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 = 2 var2 = '5' puts var1.to_s + var2 # 25 puts var1 + var2.to_i # 7 puts 9.to_f / 2 # 4.5
    • 常數 Constant ⼤大寫開頭 foo = 1 foo = 2 Foo = 1 Foo = 2 # (irb):3: warning: already initialized constant Foo RUBY_PLATFORM ENV
    • nil 表⽰示未設定值、未定義 nil # nil nil.class # NilClass nil.nil? # true 42.nil? # false nil == nil # true false == nil # false
    • 註解 # 偏好均使⽤用單⾏行註解 # this is a comment line # this is a comment line =begin This is a comment line This is a comment line =end
    • 陣列 Array a = [ 1, "cat", 3.14 ] puts a[0] # 輸出 1 puts a.size # 輸出 3 a[3] = nil puts a.inspect # 輸出字串 [1, "cat", nil]
    • 更多陣列⽅方法 colors = ["red", "blue"] colors.push("black") colors << "white" puts colors.join(", ") # red, blue, black, white colors.pop puts 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 > 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
    • 控制結構 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 = 3 puts ( 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 = 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
    • 真或假 只有 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
    • Regular Expressions 與 Perl 接近的語法 # 抓出⼿手機號碼 phone = "123-456-7890" if phone =~ /(d{3})-(d{3})-(d{4})/ ext = $1 city = $2 num = $3 end
    • ⽅方法定義 Methods def 開頭 end 結尾 def say_hello(name) result = "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower
    • ⽅方法定義 Methods def 開頭 end 結尾 def say_hello(name) result = "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower 字串相加
    • ⽅方法定義 Methods def 開頭 end 結尾 def say_hello(name) result = "Hi, " + name return result end 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.new color_array = [] # 等同 color_hash = Hash.new color_hash = {} # 等同 time = Time.new puts 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, ihower p2.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, ihower p2.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, ihower p2.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, ihower p2.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, ihower p2.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 end end p = Person.new('ihower') p.name => NoMethodError p.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, :age end class Cat < Pet end class Dog < Pet end
    • Module (1) Namespace module MyUtil def self.foobar puts "foobar" end end MyUtil.foobar # 輸出 foobar
    • 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"
    • 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 來解決 多重繼承問題
    • ⾛走訪迴圈 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 person end # 反覆五次 5.times { puts "Ruby rocks!" } # 從一數到九 1.upto(9) { |x| puts x }
    • 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 等迴圈
    • 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 word longest = ["cat", "sheep", "bear"].inject do |memo, word| ( memo.length > word.length )? memo : word end
    • 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 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!"
    • 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!"
    • 傳遞不定參數 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 / 0 rescue => e puts e.class ensure # ... 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 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
    • 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
    • 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
    • class A def foo end end obj1 = A.new obj2 = A.new what’s metaclass? obj2 Object A class super obj2 class
    • 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
    • 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!!
    • 動態型別 (duck typing) 會聒聒叫的就是鴨⼦子 # 鴨子 class Duck def quack puts "quack!" end end # 野鴨 (不用繼承) class Mallard def quack puts "qwuaacck!! quak!" end end
    • Class 不是 Type ⼀一個物件可以做什麼才是重點 birds = [Duck.new, Mallard.new, Object.new] # 迭代陣列,並呼叫方法 (無須擔心型別) birds.each do |duck| duck.quack if duck.respond_to? :quack end
    • 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 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
    • class-oriented programming v.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 end end 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 block File.open("myfile.txt", 'w') do |f| f.write("Lorem ipsum dolor sit amet") f.write("Lorem ipsum dolor sit amet") end
    • 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
    • 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
    • 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 } end end dragon = Dragon.new dragon.foo # 輸出 "bar" dragon.a # 輸出 "a" dragon.f # 輸出 "f"
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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 end end car = Car.new car.go_to_taipei # go to taipei car.blah # NoMethodError: undefined method `blah`
    • 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>
    • 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 # 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]
    • 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>'
    • 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? # false big5 =~ /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 + utf8 puts 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 (globalVM 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 changed New 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 end end 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.a PaaS (Platform as a Service)
    • 3.b ⾼高C/P值的VPS (Virtual Private Server)
    • 3.b IaaS (Infrastructure as a service) Cloud Hosing
    • 4. Consulting
    • http://www.workingwithrails.com/
    • 5. Conferences
    • 6. Books
    • http://www.pragprog.com/
    • 閱讀練習時,⼩小⼼心 Rails 版本差異 1.2, 2.0, 2.1, 2.2, 2.3, 3.0, 3,1, 3.2 4.0 書籍尚未上市
    • http://guides.rubyonrails.org/
    • 7.Video
    • http://peepcode.com/
    • 8.Website & Blog (free)
    • http://weblog.rubyonrails.org/
    • http://www.rubyinside.com/
    • http://ruby5.envylabs.com
    • http://railscasts.com/
    • http://www.rubyflow.com/
    • http://github.com/
    • 9. Ruby Community in Taiwan
    • Ruby Tuesday 聚會
    • ptt.cc #Ruby 版
    • http://railsfun.tw/
    • 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
    • We’re hiring • Ruby on Rails developer • Front-end web developer • http://faria.co