顯示具有 ruby 標籤的文章。 顯示所有文章
顯示具有 ruby 標籤的文章。 顯示所有文章

2013年4月25日 星期四

[RB] Ruby中的Proc及Block

Block:

在寫ROR時,大家或多或少會碰到這樣的語法:
posts.each do |post|
  puts post.tiltle
end
或
posts.each {|post| puts post.tiltle}
上面兩段程式碼中用do-end和大括號{}包起來的就是block,但用{}包裹程式碼的方法只適用於程式碼是一行的情況。
學ROR以來有好長一段時間我都不太清楚他的妙用,只覺得這麼普通的東西為什麼要寫的那麼拐彎抹角,但是在看了code school的教學影片後發現他跟javascript的callback機制有異曲同工之妙,這樣的設計讓我們在做一些enumeration操作的時候能將block中的code傳入,之前之所以對這個概念一直搞不清楚就是因為很難具體的想像在each中視怎麼call這段code,現在我們就用這個demo來剖開這個黑盒子:
class Child
  def initialize
    @toys=['gun','hammer','puzzle']
  end
  def each_toy
    for toy in @toys 
      yield toy
    end
  end
end

mark = Child.new
mark.each_toy do |toy|
  puts "I'm playing #{toy}~"
end

在這個範例中block像參數一樣被傳入each_toy這個method,並在裡面的loop內被多次呼叫。這樣的設計除了使用起來很靈活、有彈性以外,也能減少重複的程式碼。如果你對javascript比較了解的話可以看這一段程式碼來幫助了解:
function Child() {
    var toys = ['gun','hammer','puzzle'];
    this.eachToy = function (cb) {
        for (var _i in toys) {
            cb(toys[_i]);
        }
    }
}

mark = new Child();
mark.eachToy( function (toy) {
  console.log("I'm playing " + toy + "~");
});

但是上面的程式碼中,block看起來一點都不像是物件,也不能被重複使用。如果要像是javascript一樣能將函數像物件一樣被宣告、保存起來,並傳入其他函數作為callback function,我們還少學了一些東西,那就是接下來要介紹的Proc物件。

Proc:

proc物件可以將ruby的程式碼保存起來,在需要的時候再執行他,或當做block傳入其他函數。proc有兩種實作方法:

By Proc.new

routine = Proc.new {|variable| Do something... }
或
routine = Proc.new do |variable| 
  Do something...
end

By lambda

routine = lamda {|variable| Do something... }
或
routine = -> {|variable| Do something... }

直接執行

routine.call value


把proc轉成block

要把proc物件轉為block時,我們要在這個物件的前面加上"&",例如:
posts.each &routine

在method中判斷是否有block傳入

要知道有沒有傳入block,我們可以使用block_given?來判斷:
if block_given?
  yield
else
  puts "No block past in"
end


小結

現在我們就來改寫一下一開始的範例:
class Child
  def initialize
    @toys=['gun','hammer','puzzle']
  end
  def each_toy
    if block_given?
      for toy in @toys 
        yield toy
      end
    else
      puts "No block past in"
    end
  end
end

mark = Child.new
routine = lambda { |toy| puts "I'm playing #{toy}~" }
mark.each_toy &routine

2012年11月2日 星期五

[宅] 宅男臥軌日記(7) - .nil? , .empty?, .blank? 的區別


.nil? 和.empty? 是ruby的方法,而.blank? 是rails的方法
這三個method都是判斷是否為空值。


.nil?

判斷對象是否存在(nil)。不存在的對像都是nil的

.empty?

對象已經存在,判斷是否為空字串。
比如一個字符串是否為空串,或者一個數組中是否有值。

.blank?

具有以上兩個method的特性,railsAPI:
An object is blank if it’s false, empty, or a whitespace string. For example, “”, “ ”, nil, [], and {} are all blank.

2012年10月29日 星期一

[宅] 宅男臥軌日記(6) - %Q, %q, %W, %w, %x, %r, %s

%Q( )

能將括弧中的內容轉成雙引號框成的字串,
而%Q後面未必要用括弧,也可以是!、[ ]、+等符號,例如:
%Q! !、%Q[ ]、%Q+ +

%q( )

功能跟大寫Q差不多,只是將內容換成單引號框成的字串。

※Notice: 在Ruby中定義字串時最好使用雙引號,因為只有在雙引號中才能使用#{var}來嵌入程式碼

%W( )

將括弧中的內容轉換成雙引號的string array,看下面的程式碼會更容易理解
>> %W(#{foo} Bar Bar\ with\ space)
=> ["Foo", "Bar", "Bar with space"]

%w( )

和大寫W是差不多的,只是將雙引號變單引號


%r( )

正規表示式,如下:
>> %r(/home/#{foo})
=> "/\\/home\\/Foo/"

%s( )

用於符號(symbol)
>> %s(foo)
=> :foo
>> %s(foo bar)
=> :"foo bar"
>> %s(#{foo} bar)
=> :"\#{foo} bar"

2012年10月28日 星期日

[宅] 宅男臥軌日記(4) - class及instance的method定義

在定義class中的method時,要注意究竟是給instance使用還是class

當以如下方式定義method時,代表這個method是要給class的instance使用
class User
  def say_hello
    puts "Hello"
  end
end
所以當執行User.say_hello時就會發生找不到method的情況,但在以下情形會是正常的:
user = User.new
user.say_hello
=>"Hello"

所以如果一個method希望能被class所使用,必須以以下方式定義:
class User
  def User.say_hello
    puts "Hello"
  end
end
或是
class User
  def self.say_hello
    puts "Hello"
  end
end
當然也可以用extend從module中mixin進來

2012年10月27日 星期六

[宅] 宅男臥軌日記(2) - ruby中的include, extend及require

include vs. extend

在ruby的世界中,class只能單一繼承,而為了保有彈性,ruby提供了module的概念。
module是一個method的集合,可讓class去混入(mixin)一個module來取得這些method,而mixin的過程可用include或extend來達到。
但是include和extend的差別在哪?我們可以從以下的程式碼得知:

module Foo
  def foo
    puts 'heyyyyoooo!'
  end
end


class Bar
  include Foo
end

Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class


class Baz
  extend Foo
end

Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>

簡而言之,include是讓這個class所產生的instance繼承module中的method,有點javascript中function.prototype的味道。
extend則是讓這個class具有module中的method,卻不會繼承給instance。


require

在講require之前必須先提到load,load的作用在於將不同檔案的module給mix進來,概念上類似於C的include。而require的作用就類似於load,只是在require只會mix一次,當發現之前已經mix過同一個檔案時,require就會回傳false。
require相對load會少掉不必要的mix動作,但在module時常被更新的狀態下,最好使用load來確保自己抓到的檔案是最新的。