Demonstrates Ruby's easily misunderstood 6 features in real code _ruby topics

Source: Internet
Author: User
Tags exception handling goto instance method file permissions

Introduction: Assuming that you are a C + + developer, you need to quickly perform some prototyping with Ruby. When you pick up a ruby reference book (such as pickaxe) or browse the Ruby Web site, you'll see some familiar constructs such as class declarations, thread support, and exception handling. Just when you think you know how Ruby works, you realize that the concurrency mechanism in your Ruby code is not the same as the Boost thread, that catch and throw are quite different from what they look like, and that others use keywords named self throughout their ruby scripts 。 Welcome to Ruby's world!

If you are a C + + programmer and need to work in a Ruby environment, then you have some homework to do. This article discusses six Ruby features that a novice might misunderstand, especially if he or she comes from a similar but not identical environment, such as C + +:

Ruby class Hierarchy

A single example method in Ruby

Self keyword

Method_missing method

Exception handling

Thread

Note: All of the code in this article is tested and 1.8.7 based on the Ruby version.

Class hierarchies in Ruby

The class hierarchy in Ruby can be tricky. Create a class of Cat type and start exploring its hierarchy (see Listing 1).

Listing 1. An implicit class hierarchy in Ruby


IRB (main):092:0> class Cat
irb (main):093:1> end
=> Nil
 
irb (main):087:0> C = cat.new
=> #<cat:0x2bacb68>
IRB (main):088:0> c.class
=> Cat
irb (main):089:0> C.class.superclass
=> Object
irb (main):090:0> C.class.superclass.superclass
=> Nil
irb (main):091:0> C.class.superclass.superclass.superclass
nomethoderror:undefined method ' superclass ' for Nil:nilclass
  From (IRB):
  from:0

All objects in Ruby (and even user-defined objects) are descendants of the object class, which is clearly visible in Listing 1. This is in stark contrast to C + +. This is not the same as a normal data type, such as C + + int or double. Listing 2 shows the class hierarchy of integer 1.

Listing 2. Class hierarchy of Integer 1

IRB (main):100:0> 1.class
=> fixnum
irb (main):101:0> 1.class.superclass =>
Integer
IRB (main):102:0> 1.class.superclass.superclass
=> Numeric
irb (main):103:0> 1. Class.superclass.superclass.superclass
=> Object

So far everything goes well. Now you know that the class itself is an object of class type. Class eventually derives from Object, as shown in Listing 3, using the String class built into Ruby.

Listing 3. Class hierarchy of Classes

IRB (main):100:0> String.class
=> class
IRB (main):101:0> String.class.superclass =>
Module
IRB (main):102:0> String.class.superclass.superclass
=> Object

Module is the base class for class, but it is important to note that you cannot instantiate a user-defined Module object directly. If you don't want to delve into Ruby, it's a good idea to consider a Module with similar characteristics to the C + + namespace: You can define your own methods, constants, and so on. You include a Module in class, and all elements of voilà,module now magically become the elements of class. Listing 4 provides an example.

Listing 4. Module cannot be directly instantiated and can only be used with classes

IRB (main):020:0> module MyModule IRB (main)
:021:1> def Hello
irb (main):022:2> puts "Hello World"
IRB (main):023:2> end
IRB (main):024:1> end
IRB (main):025:0> test = mymodule.new
nomethoderror: Undefined method ' new ' for Mymodule:module from
  (IRB):
IRB (main):026:0> class MyClass
IRB (main): 0 27:1> include MyModule
IRB (main):028:1> end
=> MyClass
irb (main):029:0> test = MyClass.New
=> #<myclass:0x2c18bc8>
irb (main):030:0> Test.hello
Hello World
=> Nil

Let's reiterate the point: when you write C = Cat.new with Ruby, C is an object of the Cat type that derives from object. The Cat class is an object of class type that derives from the module, and the module derives from object. Therefore, the object and its type are valid Ruby objects.

Single-instance methods and editable classes

Now, take a look at the single example method. Suppose you want to use C + + modeling something similar to human society. So what are you going to do? Define a class named Human, and then define the Human object for millions of? It's more like a rigid society in modeling, and everyone must have unique characteristics. The single example method of Ruby is useful here, as shown in Listing 5.

Listing 5. A single example method in Ruby

IRB (main):113:0> y = human.new
=> # 
 

A single example method in Ruby is a method that is only associated with a particular object and cannot be used in a generic class. Their prefix is the object name. In Listing 5, the paint method is specific to the Y object and is limited to the Y object; Z.paint causes a "method undefined" error. You can call Singleton_methods to find a list of the single example methods in an object:

IRB (main):120:0> y.singleton_methods
=> ["Paint"]

However, there is another way to define a single case method in Ruby. Look at the code in Listing 6.

Listing 6. Another way to create a single instance method

IRB (main):113:0> y = human.new
=> # 
 

Listing 5 also opens up new possibilities for adding new methods to user-defined classes and built-in Ruby existing classes, such as String. This is not possible in C + + unless you have access to the source code of the class you are using. Observe the String class again (listing 7).

Listing 7. Ruby allows you to modify an existing class

IRB (main):035:0> y = string.new ("racecar")
=> "racecar"
IRB (main):036:0> Y.methods.grep (/ palindrome/)
=> []
irb (main):037:0> class String
irb (main):038:1> def palindrome?
IRB (main):039:2> self = = Self.reverse
irb (main):040:2> end
IRB (main):041:1> end IRB (main)
: 0 50:0> y.palindrome?
=> true

Listing 7 clearly shows how to edit an existing Ruby class to add a method of your choice. Here, I added a palindrome? method to the String class. So Ruby classes are editable at run time (a powerful attribute).

Now that you have some knowledge of Ruby's class hierarchy and the single example, let's look at self. Notice in the definition of palindrome? method, I used self.

Find self

The most common use of self keywords may be to declare a static method in a Ruby class, as shown in Listing 8.

Listing 8. To declare a static method of a class using self

Class SelfTest
 def self.test
  puts "Hello world with self!"
 End
End
 
class SelfTest2
 def Test
  puts ' This isn't a class static method '
 
End Selftest.test
Selftest2.test

As you can see from the output in Listing 8 (shown in Listing 9), there are no objects that you cannot invoke non-static methods. This behavior is similar to C + +.

Listing 9. An error occurs when calling a Non-static method without an object

IRB (main):087:0> selftest.test
Hello world with self!
=> Nil
irb (main):088:0> selftest2.test
nomethoderror:undefined method ' test ' for Selftest2:class
  From (IRB): 88

Before exploring the more esoteric uses and implications of self, note that you can also define a static method in Ruby by preceding the method name with the class name:

Class Testme
 def testme.test
  puts ' yet another static member function ' End-end
 
Testme.test # Works fine


Listing 10 provides a more interesting but not easy to find usage of self.

Listing 10. Using a meta class to declare a static method

Class MyTest
 class << self
  def test
  puts ' This is ' class static method '
 end
End
 
Mytest.test # works fine

This code defines test as a static method of a class in a slightly different way. To understand what's going on, you need to look at some of the details of class << self syntax. Class << self ... end to create a meta class. In the method lookup chain, search the object's meta class before accessing the object's base class. If you define a method in the Meta class, you can call the method on the class. This is similar to the concept of static methods in C + +.

Can I access a meta class? Yes: just return self from class << self ... end. Note that in a Ruby class declaration, you are not obligated to give only the method definition. Listing 11 shows the Meta class.

Listing 11. Understanding the Meta class

IRB (main):198:0> class MyTest
irb (main):199:1> end
=> Nil
irb (main):200:0> y = mytest.new
=> #< mytest:0x2d43fe0>
irb (main):201:0> z = Class MyTest
irb (main):202:1> class << Self
irb (main):203:2> self IRB (main)
:204:2> end
IRB (main):205:1> end
=> #<class: MyTest >
irb (main):206:0> Z.class
=> class
IRB (main):207:0> Y.class-=>


Returning to the code in Listing 7, you will see that palindrome is defined as self = = Self.reverse. In this context, self is no different from C + +. Methods in both C + + and Ruby require an action object to modify or extract state information. Self refers to this object here. Note that you can selectively invoke the public method by attaching the self prefix, indicating the object to which the method works, as shown in Listing 12.

Listing 12. Calling methods using Self

IRB (main):094:0> class SELFTEST3
irb (main):095:1> def foo-
irb (main):096:2> Self.bar ()
IRB (main :097:2> End
IRB (main):098:1> def Bar
IRB (main):099:2> puts "testing Self"
IRB (main):100:2> End
IRB (main):101:1> end
=> Nil
irb (main):102:0> test = selftest3.new
=> #<selftest3 :0x2d15750>
IRB (main):103:0> Test.foo
testing Self
=> Nil

In Ruby you cannot invoke the private method by appending the Self keyword prefix. For a C + + developer, this can be a bit confusing. The code in Listing 13 clearly indicates that self cannot be used in private methods: Calls to private methods can only be targeted at implicit objects.

Listing 13. Self cannot be used for private method calls

IRB (main):110:0> class SelfTest4
irb (main):111:1> def METHOD1
IRB (main):112:2> self.method2
IRB (main):113:2> end
IRB (main):114:1> def METHOD3
IRB (main):115:2> METHOD2
IRB (main): 116:2 > End
IRB (main):117:1> private
IRB (main):118:1> def METHOD2
IRB (main):119:2> puts "Inside Private method '
IRB (main):120:2> end
IRB (main):121:1> end
=> Nil
irb (main):122:0> y = Selftest4.new
=> #<selftest4:0x2c13d80>
irb (main):123:0> y.method1 nomethoderror
: Private method ' Method2 ' called to #<selftest4:0x2c13d80> from
  (IRB): 112:in ' method1 '
irb (main) :124:0> y.method3
Inside Private method
=> Nil

Because everything in Ruby is an object, you get the following results when you call self at the IRB prompt:

IRB (main):104:0> self
=> main
irb (main):105:0> Self.class
=> Object


The primary object is created for you as soon as the Irb,ruby interpreter is started. This main object is also referred to as the top-level context in Ruby-related articles.

So much for self. Next we look at the dynamic method and the Method_missing method.

Method_missing Secrets

Take a look at the Ruby code in Listing 14.

Listing 14. Method_missing in operation

IRB (main):135:0> class Test
irb (main):136:1> def method_missing (method, *args)
IRB (main):137:2> Puts "method: #{method} Args: (#{args.join (', ')}"
irb (main):138:2> end
IRB (main):139:1> End
=> Nil
IRB (main):140:0> t = test.new
=> #<test:0x2c7b850>
irb (main):141:0> T.f
Method:f Args: (=>)
Nil

Obviously, if Voodoo is what you like, then listing 14 will give you this grace. What's going on here? We created an object of type Test and then called T.f, with 23 as the argument. But Test does not use F as a method, you should get a nomethoderror or similar error message. Ruby is doing a great thing here: Your method calls are blocked and handled by method_missing. The first parameter of the method_missing is the missing method name, in this case F. The second (and last) argument is *args, which captures the parameters passed to F. Where can you use parameters like this? Among the many options, you can easily forward a method call to a contained module or a Component object, instead of explicitly providing a wrapper application programming interface for each call in the top-level class.

See more Voodoo in Listing 15.

Listing 15. Use the Send method to pass a parameter to a routine

IRB (main):142:0> class Test
irb (main):143:1> def method1 (S, y)
irb (main):144:2> puts "s: #{s} y: #{y}" C4/>IRB (main):145:2> end
IRB (main):146:1> end
=> Nil
irb (main): 147:0>t = test.new
irb ( Main):148:0> T.send (: Method1, a)
s:23 y:12 => Nil


In Listing 15, class Test has a method named Method1 that is defined. Instead of calling the method directly, however, the call to the Send method is issued. Send is a public method of the Object class, so it can be used with Test (remember that all classes derive from Object). The first parameter of the Send method is a symbol and a string representing the name of the method. What can the Send method do that you normally can't do? You can use the Send method to access a private method of a class. Of course, whether this is a good feature remains controversial. Take a look at the code in Listing 16.

Listing 16. Accessing class private methods

IRB (main):258:0> class Sendtest IRB (main)
:259:1> private
IRB (main):260:1> def Hello
irb (main) :261:2> puts "saying Hello privately"
IRB (main):262:2> end
IRB (main):263:1>
End => IRB (main):264:0> y = sendtest.new
=> #< sendtest:0x2cc52c0>
irb (main):265:0> Y.hello
Nomethoderror:private method ' Hello ' called to #< sendtest:0x2cc52c0> from
  (IRB): 265
IRB (main): 266:0 > y.send (: Hello)
saying hello privately
=> nil

Throw and catch are not the surface

If you have a C + + working background like me and you try to write exception-safe code, you start to feel unusually cordial when you see Ruby has throw and catch keywords. Unfortunately, the meaning of throw and catch in Ruby is completely different.

Ruby typically uses begin...rescue blocks to handle exceptions. Listing 17 provides an example.

Listing 17. Exception Handling in Ruby

Begin
 F = File.Open ("Ruby.txt")
 #. Continue File Processing
rescue ex => Exception
 #. Handle Errors , if any
ensure
 f.close unless f.nil?
 # always execute the code in ensure block end


In Listing 17, the code in the rescue block runs if there is an error in trying to open the file (possibly a problem with missing file or file permissions). The code in the ensure block is always running, regardless of whether any exceptions are raised. Note that it is optional to follow the ensure block after the rescue block. In addition, if an exception must be thrown explicitly, then the syntax is raise <MyException>. If you choose to have your own exception class, you might want to derive the same class from the Exception class built into Ruby to take advantage of existing methods.

The catch and throw code blocks in Ruby are not really exception handling: You can use throw to modify the program flow. Listing 18 shows an example of using throw and catch.

Listing 18. Throw and catch in Ruby

IRB (main):185:0> Catch:label do
irb (main): 186:1* puts ' This'll print '
irb (main):187:1> Throw:label
IRB (main):188:1> puts "This would not be print"
irb (main):189:1> end this'll
print
=> nil

In Listing 18, when the code runs to the throw statement, execution is interrupted and the interpreter begins to look for a catch block that handles the corresponding symbol. Continue execution where the catch block ends. Look at the throw and catch examples in Listing 19: Note that you can easily use catch and throw statements for individual functions.

Some even say that the support for catch and throw in Ruby takes the C goto behavior to a whole new level. Since a function can have multiple nesting layers, and a catch block may be at each level, the goto behavior analogy seems to be traceable.

Listing 19. Exception handling in Ruby: nested catch blocks

IRB (main):190:0> Catch:label do
irb (main): 191:1* Catch:label1 does
irb (main): 192:2* puts "This'll print" 
   IRB (main):193:2> Throw:label
irb (main):194:2> puts "This won ' t-print"
IRB (main):195:2>
end IRB (main):196:1> puts "Neither'll this print"
irb (main):197:1> end this'll
print
=> nil

The threads in Ruby can be green.

The Ruby version 1.8.7 does not support true concurrency. It's not really supported. But you would say that there is a Thread constructor in Ruby. You're right. However, this thread.new does not generate a real operating system thread each time you call the same method. Ruby supports green threads: The Ruby interpreter uses a single operating system thread to handle workloads from multiple application-level threads.

This "green thread" concept is useful when a thread waits for some input/output to occur, and you can easily schedule a different Ruby thread to take full advantage of the CPU. But this constructor is not able to use modern multi-core CPUs (Wikipedia provides a piece of content that nicely explains what a green thread is.) See Resources for links).

This last example (see Listing 20) demonstrates this.

Listing 20. Multiple threads in Ruby

#!/usr/bin/env Ruby
 
def func (ID, count)
 i = 0;
 while (I < count)
 puts ' Thread #{i} Time: #{time.now} ' sleep
 (1)
 i = i + 1
 end
 
puts "started" At #{time.now} "
thread1 = Thread.new{func (1)}
thread2 = Thread.new{func (2)}
thread3 = Thread.new{func (3)}
thread4 = Thread.new{func (4)}
 
thread1.join
thread2.join
Thread3.join
Thread4.join
puts "ending at #{time.now}"

Suppose you have Linux? or UNIX? It has the top utility on the machine, runs the code at the terminal, gets the process ID, and then runs Top–p <process id>. After top starts, hold down shift-h to list the number of threads running. You should see only one thread that confirms this: concurrency in Ruby 1.8.7 is just a myth.

In general, there is no harm in green threads. They are still useful in heavy load input/output-intensive programs, not to mention that the method may be the most portable among operating systems.

Conclusion

This article covers the following areas:

The concept of class hierarchies in Ruby

Single Case method

Explain self keywords and method_missing methods

exception

Thread

While Ruby is a maverick, it's interesting to use it for programming, and it's powerful to do a lot of work with minimal code. No wonder a large application like Twitter uses Ruby to harness its real potential. Wish you have a happy Ruby programming experience!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.