2014年11月5日 星期三

[ 文章收集 ] Ruby Exceptions And Exception Handling

Source From Here 
Preface 
Ruby exceptions and error handling is not the most remarkable feature of the Ruby language. Infact, the way Ruby deals with exceptions is strikingly similar to other languages (such as Java etc.). But, I think all the stuff I’ve been writing about Ruby lately has taken on a life of it’s own for me :), so I am going to quickly go over this topic if only for completeness sakes. 

Raising Exceptions 
Getting Ruby to raise an exception is easy :). Ruby, like many other languages has a hierarchy of exception classes (that all inherit from the class Exception), some of these are familiar and fairly easy to produce, for example ZeroDivisionError or NoMethodError. Here is some code which will do just that: 
 

Of course you don’t have to wait for Ruby to raise exceptions for you, you can do so explicitly in your code with the raise keyword (it is actually a method). Lets write a method where we explicitly raise an exception if the argument we pass in is false: 
  1. def i_must_have_truth(value)  
  2.   raise TypeError, 'You must give me truth' if value == false  
  3. end  
  4.   
  5. i_must_have_truth false  
this prints: 
 

As you can see we are able to raise a specific exception and pass it a message which then gets printed out to the console. There is also a handy shortcut, if you use raise without giving it a specific exceptions (or even without giving it an error message to display), Ruby will automatically raise a RuntimeError for you which is pretty handy: 
  1. def i_must_have_truth(value)  
  2.   raise "Hello"  
  3. end  
  4.   
  5. i_must_have_truth false  
this prints: 
 

Rescuing Exceptions 
So far so good, but life would be pretty tough if we couldn’t handle the exceptions that get thrown in any way, This is where the rescue clause comes in. If we wrap some code in a begin .. end block and put a rescue clause in the middle of that, control will go to the rescue clause if any exception is thrown by the code. Let us demonstrate: 
  1. begin  
  2.   1/0  
  3.   p 'I should never get executed'  
  4. rescue  
  5.   p 'I am rescuing an exception and can do what I want!'  
  6. end  
This produces the following output: 
"I am rescuing an exception and can do what I want!"

As you can see the first string does not get printed since the division by zero will throw an exception and control will pass to the rescue clause, which will print out the second string for us. Using rescue by itself will allow you to rescue all exceptions that get thrown by the code, but sometimes you might want to only capture specific ones and let other code handle all the others. The rescue clause allows you to do this as well: 
  1. i=0  
  2. while i<=10  
  3.   begin  
  4.     if i ==0  
  5.       1/0  
  6.     end  
  7.     raise "random runtime exception"  
  8.     p 'I should never get executed'  
  9.   rescue ZeroDivisionError  
  10.     p 'I am rescuing only ZeroDivisionErrors!'  
  11.     i+=1  
  12.   end  
  13. end  
which gives us: 
 

As you can tell, we rescued the first exceptions since it was a division by zero, but the second exception does not get rescued and so the program exits with an error. However, we sometimes want to execute some code regardless of whether an exception was thrown or not (i.e. we may want to do some cleanup). Java has the finallykeyword for this, Ruby has ensure. We can put an ensure clause within out begin .. end block. The code inside this clause gets executed regardless of whether the code throws an exception or not. For example, if we are reading from a file, we want to close the file handle no matter if an exception is thrown or not, we can do the following: 
  1. file = nil  
  2. begin  
  3.   file = File.open("blah.txt")  
  4.   raise  
  5. rescue  
  6.   p 'I rescue all exception and raise new ones'  
  7. ensure  
  8.   file.close if file!=nil  
  9.   p 'just closed the file'  
  10. end  
as we expect the output is: 
"I rescue all exception and raise new ones"
"just closed the file"
Even though an exception was thrown and rescued, the code in the ensure clause executes regardless. 

Rescuing Exceptions Inside Methods 
If we are inside a method and we want to rescue some exceptions, we don’t actually need a begin .. end block since the method definition itself will act in that capacity. So, we can do something like this: 
  1. def some_method  
  2.   p 'Hello method'  
  3.   raise  
  4.   p 'Bye method'  
  5. rescue  
  6.   p 'Rescuing exceptions'  
  7. end  
  8. some_method  
which print out: 
"Hello method"
"Rescuing exceptions"

We have rescued an exceptions without having a begin .. end block. 

You are not limited to knowing just the type of the exception you’re rescuing, you can get more information at your disposal. When you rescue an exception you can get a hold of the actual exception object that was thrown and then query this object for various details. Here is how: 
  1. begin  
  2.   raise ZeroDivisionError, "Hello I am a random zero division error"  
  3. rescue ZeroDivisionError => e  
  4.   p e.message  
  5.   p e.backtrace  
  6. end  
Execution result: 
"Hello I am a random zero division error"
["C:\\John\\EclipseNTU\\RubyAlg\\Test.rb:2:in `(root)'"]

If we execute the above code we will print out the message as well as the stack trace of the exception we rescued which are provided by the exception object itself. You can also do the same thing with a general rescue clause: 
  1. begin  
  2.   raise "Hello I am a random runtime error"  
  3. rescue => e  
  4.   p e.message  
  5.   p e.backtrace  
  6. end  
Finally if you have rescued an exception, but don’t want to handle it yourself (for whatever strange reason), calling raise within a rescue block with no parameters will allow you to re-raise the original exception that you have rescued rather than the normal behavior (i.e. raising a general runtime exception). 

Creating Your Own Exceptions 
Creating your own exceptions in Ruby is extremely simple, all you need to do is create a class that inherits from Exception or one of it’s descendants and you’re good to go: 
  1. class MyCrazyException < Exception  
  2. end  
  3.   
  4. raise MyCrazyException, "I am a crazy new exception"  
this prints out: 
 

As you can see Ruby is saying that it has raised our new exception rather than one of it’s regular ones. As usual, this allows you to define different types of exceptions for various error conditions in your code which also allows you to rescue them by name. You may or may not want to do this, you can easily get away with just using runtime exceptions but it is up to you. 
Update. 
Several people have pointed out, in the comments that inheriting from Exception directly is a big no-no when creating custom exceptions. You should instead inherit fromStandardError. This is because exceptions that inherit from StandardError deal with application level errors, while if you inherit Exception directly you risk catching errors to do with the environment. Also the convention is to end your exceptions with the word Error rather than exceptions e.g.:
  1. class MyCrazyError < StandardError  
  2. end  

The Ruby Exception Hierarchy 
If you’re curious about the kinds of exceptions that Ruby has predefined for you, here is a list: 
 

The only thing that is missing from that list is the Errno family of exceptions. These are a whole set of exceptions that relate to file I/O and live in the Errno namespace. You can see one of these in action if you try to open a file that doesn’t exist, e.g.: 
which gives you an Errno style exception: 
 

You’re now a Ruby exception guru, go forth and use your new Ruby error handling powers for good instead of evil :). 

Supplement 
* Ruby 手冊 - 救援 Exception processing: rescue 
* Ruby 手冊 - 確認 Exception processing: ensure

2014年11月4日 星期二

[ Ruby Gossip ] Basic : 類別 - 類別變數

Source From Here 
Preface 
接續 單例方法、實例方法、類別方法 的討論。個別類別可以擁有自己的類別方法,也可以擁有自己的類別變數(Class variable),只要變數前加上 @@ 符號就可以定義類別變數。例如: 
 

上例中定義了 Some 的類別變數 @@s,預設外界是不可以直接存取類別變數,你必須為類別變數定義類別方法,外界才可存取,如上例所示。 

類別變數 
可以在實例方法中使用類別變數,不過,你不能在類別方法中使用實例變數,因為類別方法屬於類別擁有,但實例變數屬於實例擁有,類別方法中無法單就 @name 來識別該取得哪個實例的變數值: 
 

在頂層範圍中,如果你如下定義: 
相當於如此定義: 
  1. class Object  
  2.     X = 10  
  3. end  
這可以如下證實: 
>> X = 20
=> 20
>> X
=> 20
>> Object::X
=> 20

類似地,如果你如下定義: 
  1. y = 5  
  2. @@y = 10  
相當於如下定義: 
  1. class Object  
  2.     y = 5  
  3.     @@y = 10  
  4. end  
這可以如下證實: 
 

在 變數範圍 談過,區域變數的範圍就是該區塊,因此上例中 y 是不能在 show_y 中可見的。 

類別既然為 Class 實例,而類別方法實際上為 Class 實例上的單例方法,那麼類別變數就是 Class 實例的實例變數嗎?答案是否定的! Class 實例還是可以擁有自己的實例變數。例如: 
 

@@ 開頭的變數之所以稱為類別變數,是因為它定義了類別範圍內可見的變數,而不是定義 Class 實例的實例變數。注意,@@ 開頭的變數是定義在哪個類別中,它的可視範圍就是在該類別。例如以下是可行的: 
 

@@s 是定義在 Some 中,所以在整個 Some 中都是可見的,不過以下這個範例有個陷阱: 
 

Some 中的 @@s 確實是指在 Some 中可見的類別變數,但是你在頂層定義 Some.s 時,實際上是等同於: 
  1. class Object  
  2.     ...  
  3.     def Some.s  
  4.         @@s  
  5.     end  
  6. end  
這時的 @@s 是想取得 Object 中的 @@s,當然就看不到而發生錯誤,注意以上的 NameError 中的訊息,就是 uninitialized class variable @@s in Object,而不是uninitialized class variable @@s in Some。再來看個有趣的實驗: 
 
定義在 Some.x 中的 @@x,經由 Object.x 中的 @@x 取得的值是相同的。 

注意,在頂層或者說是 Object 類別中,若有 @@變數 與內部類別的 @@變數 同名,則內部類別的 @@變數 會覆蓋外部類別的 @@變數。例如: 
 

這相當於: 
 

但是在非頂層或 Object 中的行為則不同,內部類別的 @@變數「不會」覆蓋外部類別的@@同名變數。例如 
 

Supplement 
* Ruby 手冊 - 類別常數

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...