Ruby程式语言-入门


Ruby 程式語言 入門導覽 ihower@gmail.com 2011/3 Monday, March 7, 2011 我是誰 ? • 張文鈿 a.k.a. ihower • http://ihower.tw • http://twitter.com/ihower • Rails Developer since 2006 • The organizer of Ruby Taiwan Community • http://ruby.tw Monday, March 7, 2011 什麼是 Ruby? • 開放原碼、物件導向的動態直譯式 (interpreted)程式語言 • 簡單哲學、高生產力 • 精巧、自然的語法 • 創造者 Yukihiro Matsumoto, a.k.a. Matz • 靈感來自 Lisp, Perl, 和 Smalltalk • 設計的目的是要讓程式設計師 Happy Monday, March 7, 2011 馬斯洛需求層次理論 生理 安全 社交 尊重 自我實現 Happy? DHH(Rails creator) Monday, March 7, 2011 Monday, March 7, 2011 Monday, March 7, 2011 irb: Interactive Ruby 馬上動手練習 irb(main):001:0> irb(main):001:0> 1 + 1 => 2 irb(main):002:0> Monday, March 7, 2011 PUTS 螢幕輸出 • 打開編輯器,編輯 hello.rb • 執行 ruby number.rb puts "Hello World!" Monday, March 7, 2011 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++ Monday, March 7, 2011 什麼強 ?弱 ?分型 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: Monday, March 7, 2011 Part1: 基礎語法 Monday, March 7, 2011 整數 Integer 5 -205 9999999999 0 Monday, March 7, 2011 浮點數 Float 後面有 . 54.321 0.001 -12.312 0.0 Monday, March 7, 2011 浮點數四則運算 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 Monday, March 7, 2011 整數四則運算 結果也會是整數 puts 1 + 2 puts 2 * 3 puts 5 - 8 puts 9 / 2 # 3 # 6 # -1 # 4 Monday, March 7, 2011 更多運算 puts 5 * (12-8) + -15 puts 98 + (59872 / (13*8)) * -52 Monday, March 7, 2011 字串 String puts 'Hello, world!' puts '' puts 'Good-bye.' Monday, March 7, 2011 字串處理 puts 'I like ' + 'apple pie.' puts 'You\'re smart!' puts '12' + 12 # Monday, March 7, 2011 更多字串方法 var1 = 'stop' var2 = 'foobar' var3 = "aAbBcC" puts var1.reverse # 'pots' puts var2.length # 6 puts var3.upcase puts var3.downcase Monday, March 7, 2011 Ruby 完全地物件導向 每樣東西都是物件,包括字串和數字。 # 輸出 "UPPER" puts "upper".upcase # 輸出 -5 的絕對值 puts -5.abs # 輸出 Fixnum puts 99.class # 輸出 "Ruby Rocks!" 五次 5.times do puts "Ruby Rocks!" end Monday, March 7, 2011 方法呼叫 Methods • 所有東西都是物件 (object),可以呼叫物 件的方法,例如字串、整數、浮點數。 • 透過逗點 . 來對物件呼叫方法 Monday, March 7, 2011 變數 Variable 小寫開頭,偏好單字之間以底線 _ 分隔 composer = 'Mozart' puts composer + ' was "da bomb", in his day.' my_composer = 'Beethoven' puts 'But I prefer ' + my_composer + ', personally.' Monday, March 7, 2011 型別轉換 Conversions var1 = 2 var2 = '5' puts var1.to_s + var2 # 25 puts var1 + var2.to_i # 7 puts 9.to_f / 2 # 4.5 Monday, March 7, 2011 常數 Constant 大寫開頭 foo = 1 foo = 2 Foo = 1 Foo = 2 # (irb):3: warning: already initialized constant Foo RUBY_PLATFORM ENV Monday, March 7, 2011 nil 表示未設定值、未定義 nil # nil nil.class # NilClass nil.nil? # true 42.nil? # false nil == nil # true false == nil # false Monday, March 7, 2011 註解 # 偏好均使用單行註解 # this is a comment line # this is a comment line =begin This is a comment line This is a comment line =end Monday, March 7, 2011 陣列 Array a = [ 1, "cat", 3.14 ] puts a[0] # 輸出 1 puts a.size # 輸出 3 a[2] = nil puts a.inspect # 輸出 [1, "cat", nil] Monday, March 7, 2011 更多陣列方法 colors = ["red", "blue"] colors.push("black") colors << "white" puts colors.join(", ") # red, blue, black, white colors.pop puts colors.last #black Monday, March 7, 2011 雜湊 Hash (Associative Array) config = { "foo" => 123, "bar" => 456 } puts config["foo"] # 輸出 123 Monday, March 7, 2011 字串符號 Symbols 唯一且不會變動的識別名稱 config = { :foo => 123, :bar => 456 } puts config[:foo] # 輸出 123 Monday, March 7, 2011 流程控制 Flow Control Monday, March 7, 2011 比較方法 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 Monday, March 7, 2011 控制結構 If if account.total > 100000 puts "large account" elsif account.total > 25000 puts "medium account" else puts "small account" end Monday, March 7, 2011 控制結構 If if account.total > 100000 puts "large account" elsif account.total > 25000 puts "medium account" else puts "small account" end Perl Style Monday, March 7, 2011 三元運算子 expression ? true_expresion : false_expression x = 3 puts ( x > 3 )? "大於三 " : "小於或等於三 " # 輸出 小於或等於三 Monday, March 7, 2011 控制結構 Case case name when "John" puts "Howdy John!" when "Ryan" puts "Whatz up Ryan!" else puts "Hi #{name}!" end Monday, March 7, 2011 迴圈 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 Monday, March 7, 2011 真或假 只有 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 Monday, March 7, 2011 Regular Expressions 與 Perl 接近的語法 # 抓出手機號碼 phone = "123-456-7890" if phone =~ /(\d{3})-(\d{3})-(\d{4})/ ext = $1 city = $2 num = $3 end Monday, March 7, 2011 方法定義 Methods def 開頭 end 結尾 def say_hello(name) result = "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower Monday, March 7, 2011 方法定義 Methods def 開頭 end 結尾 def say_hello(name) result = "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower 字串相加 Monday, March 7, 2011 方法定義 Methods def 開頭 end 結尾 def say_hello(name) result = "Hi, " + name return result end puts say_hello('ihower') # 輸出 Hi, ihower 字串相加 return 可省 略,最後一行 就是回傳值 Monday, March 7, 2011 ? 與 ! 的慣例 方法名稱可以用 ?或 !結尾,前者表示會回傳 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] Monday, March 7, 2011 類別 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 Monday, March 7, 2011 類別 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 Monday, March 7, 2011 類別 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 建構式 Monday, March 7, 2011 類別 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 建構式 物件變數 Monday, March 7, 2011 類別 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 建構式 物件變數 字串相加 Monday, March 7, 2011 類別 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 建構式 物件變數 字串相加 大寫開頭的 常數 Monday, March 7, 2011 類別 Class (續 ) class Person @@name = “ihower” def self.say puts @@name end end Person.say # 輸出 Hello, ihower Monday, March 7, 2011 類別 Class (續 ) class Person @@name = “ihower” def self.say puts @@name end end Person.say # 輸出 Hello, ihower 類別變數 Monday, March 7, 2011 類別 Class (續 ) class Person @@name = “ihower” def self.say puts @@name end end Person.say # 輸出 Hello, ihower 類別變數 類別方法 Monday, March 7, 2011 資料封裝 • 所有的物件變數 (@開頭 )、類別變數 (@@開頭 ), 都是封裝在類別內部,類別外無法存取。 • 需透過定義 public 方法才可以存取到 class Person def initialize(name) @name = name end end p = Person.new('ihower') p.name => NoMethodError p.name='peny' => NoMethodError Monday, March 7, 2011 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" Monday, March 7, 2011 方法封裝 預設是 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 Monday, March 7, 2011 類別 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 等同於 Monday, March 7, 2011 Class 繼承 class Pet attr_accessor :name, :age end class Cat < Pet end class Dog < Pet end Monday, March 7, 2011 走訪迴圈 each method languages = ['Ruby', 'Javascript', 'Perl'] languages.each do |lang| puts 'I love ' + lang + '!' end # I Love Ruby # I Love Javascript # I Love Perl Monday, March 7, 2011 迭代器 iterator • 不同於 while 迴圈用法, each 是一個陣 列的方法,走訪其中的元素,我們稱作 迭代器 (iterator) • 其中 do .... end 是 each 方法的參數,稱 作匿名方法 ( code block) Monday, March 7, 2011 最簡單的迭代器 3.times do puts 'Good Job!' end # Good Job! # Good Job! # Good Job! Monday, March 7, 2011 code block 一種匿名方法,或稱作 closure { puts "Hello" } # 這是一個 block do puts "Blah" # 這也是一個 block puts "Blah" end Monday, March 7, 2011 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 } Monday, March 7, 2011 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 等迴圈 Monday, March 7, 2011 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] Monday, March 7, 2011 code block 當作判斷條件 # 迭代並根據條件刪除 a = [ "a", "b", "c" ] a.delete_if {|x| x >= "b" } # 結果 是 ["a"] # 客製化排序 [2,1,3].sort! { |a, b| b <=> a } # 結果 是 ["3",”2”,”1”] Monday, March 7, 2011 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 Monday, March 7, 2011 code block 僅執行一次呼叫 file = File.new("testfile", "r") # ...處理檔案 file.close File.open("testfile", "r") do |file| # ...處理檔案 end # 檔案自動關閉 Monday, March 7, 2011 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" Monday, March 7, 2011 帶參數的 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!" Monday, March 7, 2011 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!" Monday, March 7, 2011 傳遞不定參數 def my_sum(*val) val.inject(0) { |sum, v| sum + v } end puts my_sum(1,2,3,4) # 輸出 10 Monday, March 7, 2011 參數尾 Hash 可省略 { } def my_print(a, b, options) puts a puts b puts options[:x] puts options[:y] puts options[:z] end puts my_print("A", "B", { :x => 123, :z => 456 } ) puts my_print("A", "B", :x => 123, :z => 456) # 結果相同 # 輸出 A # 輸出 B # 輸出 123 # 輸出 nil # 輸出 456 Monday, March 7, 2011 例外處理 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 Monday, March 7, 2011 Module (1) Namespace module MyUtil def self.foobar puts "foobar" end end MyUtil.foobar # 輸出 foobar Monday, March 7, 2011 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 include AwesomeModule # ... end ph = Foo.new("12312312") et = Bar.new("78678678") ph.who_am_i? # 輸出 "Foo (#330450): 12312312" et.who_am_i? # 輸出 "Bar (#330420): 78678678" Monday, March 7, 2011 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 include AwesomeModule # ... 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 來解決 多重繼承問題 Monday, March 7, 2011 動態型別 (duck typing) 會聒聒叫的就是鴨子 # 鴨子 class Duck def quack puts "quack!" end end # 野鴨 (不用繼承 ) class Mallard def quack puts "qwuaacck!! quak!" end end Monday, March 7, 2011 Class 不是 Type 一個物件可以做什麼才是重點 birds = [Duck.new, Mallard.new, Object.new] # 迭代陣列,並呼叫方法 (無須擔心型別) birds.each do |duck| duck.quack if duck.respond_to? :quack end Monday, March 7, 2011 Class 不是 Type 一個物件可以做什麼才是重點 birds = [Duck.new, Mallard.new, Object.new] # 迭代陣列,並呼叫方法 (無須擔心型別) birds.each do |duck| duck.quack if duck.respond_to? :quack end 這不就是 OOP多型, 超簡單 ! Monday, March 7, 2011 Metaprogramming 用程式寫程式 Monday, March 7, 2011 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" Monday, March 7, 2011 Domain-Specific Language (一個 Rails 的使用範例 ) 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 Monday, March 7, 2011 Method Missing class Proxy def initialize(object) @object = object end def method_missing(symbol, *args) @object.send(symbol, *args) end end object = ["a", "b", "c"] proxy = Proxy.new(object) puts proxy.first # Proxy 並沒有 first 這個方法,將執行 method_missing,並輸出 "a" Monday, March 7, 2011 Introspection (反射機制 ) # 這個物件有什麼方法 Object.methods => ["send", "name", "class_eval", "object_id", "new", "singleton_methods", ...] # 這個物件有這個方法嗎? Object.respond_to? :name => true Monday, March 7, 2011 Part2: 應用練習 gem install sinatra -y --no-ri --no-rdoc gem install nokogiri -y --no-ri --no-rdoc Monday, March 7, 2011 RubyGems • Ruby 的套件管理工具 • gem list 可以顯示目前安裝的套件 • 更多套件 http://rubygems.org/ Monday, March 7, 2011 Sinatra • 一套非常輕量的 web development 工具 • http://www.sinatrarb.com/ • gem install sinatra Monday, March 7, 2011 第一隻 web app 執行 ruby myapp.rb,然後打開瀏覽器 http://localhost:4567 # myapp.rb require 'rubygems' require 'sinatra' get '/' do 'Hello world!' end Monday, March 7, 2011 解析 URL 參數 require 'rubygems' require 'sinatra' get '/hello/:name' do # 符合 "GET /hello/foo" 或 "GET /hello/bar" # params[:name] 就會是 'foo' 或 'bar' "Hello #{params[:name]}!" end Monday, March 7, 2011 使用 template 建立 views 目錄,加入 hello.erb 檔案 # myapp.rb require 'rubygems' require 'sinatra' get '/hello/:name' do erb :hello end Monday, March 7, 2011 ERB (Ruby Template) Sinatra app <% 10.times do %>

<%= "Hello #{params[:name]}!" %>

<% end %> Monday, March 7, 2011 傳遞變數到 Template # myapp.rb require 'rubygems' require 'sinatra' get '/array' do @arr = ["aaa","bbb","ccc","ddd"] erb :array end # views/array.erb <% @arr.each do |item| %>

<%= item %>

<% end %> Monday, March 7, 2011 表單製作 # views/index.erb

# myapp.rb require 'rubygems' require 'sinatra' get '/' do erb :index end post '/query' do params[:keyword] end Monday, March 7, 2011 nokogiri • HTML, XML, SAX 解析工具 (parser) • 使用 XPath 或 CSS 選取想要的資料 • gem install nokogiri Monday, March 7, 2011 require 'rubygems' require 'nokogiri' text = "
  • FOOOBARRR
  • AAAAACCCCC
    • " doc = Nokogiri::HTML(text) puts doc.css('li').size # 2 doc.css('li').each do |item| puts item.content end # FOOOBARRR # AAAAACCCCC Monday, March 7, 2011 sinatra+nokogiri 應用 抓取目標網頁的所有超連結 # myapp.rb require 'rubygems' require 'sinatra' require 'nokogiri' require 'open-uri' get '/' do erb :index end post '/query' do html = open( params[:keyword] ).read doc = Nokogiri::HTML(html) @links = doc.css('a') erb :query end Monday, March 7, 2011
        <% @links.each do |link| %>
      • <%= link.content %> <%= link.attributes["href"] %>
      • <% end %>
      Monday, March 7, 2011 Thank you. 參考資料: Beginning Ruby 2nd. (Apress) Programming Ruby (The Pragmatic Programmers) The Well-Grounded Rubyist (Manning) Ruby 程式設計 (O’Reilly) Foundation Rails 2 (friendsof) Monday, March 7, 2011
还剩97页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

n5bn

贡献于2016-02-19

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf