Wednesday, 27 August 2008

The Ruby Way By Hal Fulton - Final Part

Couple of Days back i started reading The Ruby Way By Hal Fulton

Today i have read remaining chapters from the book and I wanted to share few important quotations i found from these chapters.

Finally we need to congratulate author for this great book.

1) Creating Threads
Creating a thread is easy. Simply call the new method and attach a block that will be the body of the thread.

thread = Thread.new do
# Statements comprising
# the thread...
end

2) Accessing Thread-local Variables

What if a thread wants to "make public" some of the data that it owns?

There is a special mechanism for this purpose. If a thread object is treated as a hash, thread-local data can be accessed from anywhere within the scope of that thread object. We don't mean that actual local variables can be accessed in this way, but only that we have access to named data on a per-thread basis.

There is also a method called key? that will tell us whether a given name is in use for this thread.

Within the thread, we must refer to the data in the same hashlike way. Using Thread.current will make this a little less unwieldy.

thread = Thread.new do
t = Thread.current
t[:var1] = "This is a string"
t[:var2] = 365
end

# Access the thread-local data from outside...

x = thread[:var1] # "This is a string"
y = thread[:var2] # 365

has_var2 = thread.key?("var2") # true
has_var3 = thread.key?("var3") # false

3) Besides a symbol (as we just saw) we can also use a string to identify the thread-local variable.

thread = Thread.new do
t = Thread.current
t["var3"] = 25
t[:var4] = "foobar"
end

a = thread[:var3] = 25
b = thread["var4"] = "foobar"

4) Querying and Changing Thread Status

The THRead class has several class methods that serve various purposes. The list method returns an array of all living threads; the main method returns a reference to the main thread, which spawns the others; and the current method allows a thread to find its own identity.

t1 = Thread.new { sleep 100 }
t2 = Thread.new do
if Thread.current == Thread.main
puts "This is the main thread." # Does NOT print
end
1.upto(1000) { sleep 0.1 }
end

count = Thread.list.size # 3
if Thread.list.include?(Thread.main)
puts "Main thread is alive." # Always prints!
end
if Thread.current == Thread.main
puts "I'm the main thread." # Prints here...
end

5) The special method pass is used when a thread wants to yield control to the scheduler. The thread merely yields its current timeslice; it doesn't actually stop or go to sleep.

t1 = Thread.new do
puts "alpha"
Thread.pass
puts "beta"
end
t2 = Thread.new do
puts "gamma"
puts "delta"
end

t1.join
t2.join

6) A thread that is stopped may be awakened by use of the run or wakeup methods:

t1 = Thread.new do
Thread.stop
puts "There is an emerald here."
end
t2 = Thread.new do
Thread.stop
puts "You're at Y2."
end
sleep 1
t1.wakeup
t2.run

7) Sometimes the main thread wants to wait for another thread to finish. The instance method join will accomplish this.

t1 = Thread.new { do_something_long() }

do_something_brief()
t1.join # Wait for t1


Note that a join is necessary if the main thread is to wait on another thread. When the main thread exits, a thread is killed otherwise. For example, the following code fragment would never give us its final answer without the join at the end:

meaning_of_life = Thread.new do
puts "The answer is..."
sleep 10
puts 42
end

sleep 9
meaning_of_life.join

8) A thread has an associated block, and a block can have a return value. This implies that a thread can return a value. The value method will implicitly do a join operation and wait for the thread to complete; then it will return the value of the last evaluated expression in the thread.

max = 10000
thr = Thread.new do
sum = 0
1.upto(max) { |i| sum += i }
sum
end

guess = (max*(max+1))/2
print "Formula is "
if guess == thr.value
puts "right."
else
puts "wrong."
end

9) Performing Simple Synchronization with Critical Sections

The simplest form of synchronization is to use a critical section. When a thread enters a critical section of code, this technique guarantees that no other thread will run until the first thread has left its critical section.

The THRead.critical accessor, when set to TRue, will prevent other threads from being scheduled. In the following code, we revisit the previous example and use the critical accessor to define the critical section and protect the sensitive parts of the code.

x = 0
t1 = Thread.new do
1.upto(1000) do
Thread.critical = true
x = x + 1
Thread.critical = false
end
end

t2 = Thread.new do
1.upto(1000) do
Thread.critical = true
x = x + 1
Thread.critical = false
end
end

t1.join
t2.join
puts x

10) REXML is a pure-Ruby XML processor conforming to the XML 1.0 standard. It is a nonvalidating processor, passing all of the OASIS nonvalidating conformance tests.

Example:


<library shelf="Recent Acquisitions">
<section name="Ruby">
<book isbn="0672328844">
<title>The Ruby Way</title>
<author>Hal Fulton</author>
<description>Second edition. The book you are now reading.
Ain't recursion grand?
</description>
</section>
<section name="Space">
<book isbn="0684835509">
<title>The Case for Mars</title>
<author>Robert Zubrin</author>
<description>Pushing toward a second home for the human
race.
</description>
</book>
<book isbn="074325631X">
<title>First Man: The Life of Neil A. Armstrong</title>
<author>James R. Hansen</author>
<description>Definitive biography of the first man on
the moon.
</description>
</book>
</section>
</library>



require 'rexml/document'
include REXML

input = File.new("books.xml")
doc = Document.new(input)

root = doc.root
puts root.attributes["shelf"] # Recent Acquisitions

doc.elements.each("library/section") { |e| puts e.attributes["name"] }
# Output:
# Ruby
# Space

doc.elements.each("*/section/book") { |e| puts e.attributes["isbn"] }
# Output:
# 0672328844
# 0321445619
# 0684835509
# 074325631X

sec2 = root.elements[2]
author = sec2.elements[1].elements["author"].text # Robert Zubrin

11) Creating PDF Documents with PDF::Writer

PDF::Writer is a library to create PDF documents in Ruby.

require "pdf/writer"

pdf = PDF::Writer.new
pdf.select_font "Times-Roman"
pdf.text "Hello, Ruby.", :font_size => 72, :justification => :center
pdf.save_as("hello.pdf")

12) This article is fine regarding Creating Printable Documents with Ruby.

13) Web Resources
The main Ruby site is www.ruby-lang.org, from which all others should be reachable in a few hops. The latest version of Ruby itself can always be obtained here.

Another important site is rubygarden.org, which used to be purely wiki-based. The wiki is still there, but there is also a moderated section with many useful articles and tutorials.

For documentation, don't miss ruby-doc.org, maintained by James Britt. It hosts a wealth of rdoc output for the core and standard libraries as well as other useful items.

RubyCentral is a nonprofit devoted to Ruby advocacy (rubycentral.org). Among other things, this group is in charge of the International Ruby Conference each year. Since it has 501(c)3 status, U.S. citizens may make tax-exempt contributions to this organization.

Don't confuse this site with rubycentral.com, which is unrelated. This is another excellent Ruby site, one of the first in English, created by the Pragmatic Programmers


About the Author

Hal Fulton has two degrees in computer science from the University of Mississippi. He taught computer science for four years at the community college level before moving to Austin, Texas, for a series of contracts (mainly at IBM Austin). He has worked for more than 15 years with various forms of UNIX, including AIX, Solaris, and Linux. He was first exposed to Ruby in 1999, and in 2001 he began work on the first edition of this book, which was the second Ruby book in the English language. He has attended six Ruby conferences and has given presentations at four of those, including the first European Ruby Conference in Karlsruhe, Germany. He currently works at Broadwing Communications in Austin, Texas, working on a large data warehouse and related telecom applications. He works daily with C++, Oracle, and of course, Ruby.

Hal is still active daily on the Ruby mailing list and IRC channel, and has several Ruby projects in progress. He is a member of the ACM and the IEEE Computer Society. In his personal life, he enjoys music, reading, writing, art, and photography. He is a member of the Mars Society and is a space enthusiast who would love to go into space before he dies. He lives in Austin, Texas.

No comments: