Ruby—A Diamond of a Programming Language, Part 2

uby is an object-oriented, metaprogramming language that has garnered a lot of attention in software development circles as of late. Metaprogramming is a means of writing software programs that write or manipulate other programs, thereby making coding faster and more reliable. Part 1 examined Ruby setup, general syntax, and object-oriented aspects. This article, part 2, looks at some other powerful features built into the Ruby programming language. Again, Ruby is based on and has adopted features from many languages including Lisp, Smalltalk, Python and Perl. So in many ways, Ruby is a “best of breed” language that has been assembled from the best and most powerful programming features found in its predecessors.

Numbers, Strings, and other “Standard” Types in Ruby
Everything in Ruby is an object. Maybe more precisely, everything in Ruby is treated as a full fledged object. So, the number 4, the fixed point number 3.14 and the string “Hi” are all objects in Ruby. Obviously, they are somewhat “special” objects since you don’t have to use the new method to create one. Instead, you use the literal 4, for example, to create an instance of the object representing the number 4.

However, when most people learn a new programming language it is helpful to understand “standard” types. So in this section, numbers, strings, Booleans, and a few other base Ruby types are explored.

Numerics
Essentially, numbers in Ruby are classified as either integers or floats. Integers are further subdivided. There are “regular sized” integers and really big integers. Because everything is an object, floats and integers (whether big or small) are defined by classes (see Figure 1). Numeric is the super class for all numbers. Float and Integer classes are subclasses of Numeric. Fixnum and Bignum are subtypes of Integer that define the “regular size” and bigger integer numbers.

Figure 1. Ruby Numbers: The Numeric class is the super class for all Ruby numbers. Concrete instances of numbers are either of type Bignum or Fixnum integers or Float.

Literals are used to represent instances of these classes. The code below in the interactive Ruby shell (irb) shows literal instances of Float, Fixnum and Bignum. Notice that methods (in this case the class method) can be called on the literal. Again, everything in Ruby is an object so you will find all sorts of methods for numeric instances.

irb(main):001:0> 3.class=> Fixnumirb(main):002:0> 3.4.class=> Floatirb(main):003:0> 10000000000000000000.class=> Bignum

There is some additional syntax for creating numbers as shown in the code listing below. The letter ‘E’ can be used to represent numbers in exponential notation. Numbers can be proceeded with 0 to represent a number in octal, 0x to represent a number in hex, and 0b to represent a number in binary form. For clarity, underscores can be used in numbers as separators. Be careful not to use a comma as a separator when writing literals. In some cases, this can actually produce an array, which will be discussed below. Finally, a question mark in front of a character (or control or meta character combination) creates a Fixnum instance corresponding to the ASCII character/escape sequence value for the character(s).

 3.14E5 #exponential notation=> 314000.0irb(main):002:0> 054	 #octal=> 44irb(main):003:0> 0x5A #hex=> 90irb(main):004:0> 0b1011 #binary=> 11irb(main):005:0> 10_000 #10,000 with underscore separator=> 10000irb(main):006:0> i=10,000 #creates an array not 10000 Fixnum=> [10, 0]irb(main):007:0> i.class=> Arrayirb(main):008:0> ?Z #Fixnum ASCII value=> 90irb(main):009:0> ?Z.class=> Fixnumirb(main):010:0> ?C-s #ASCII value of Control-s=> 19

What’s the real difference between Fixnum and Bignum instances? Fixnum integers can be stored in the machines word minus a bit (usually 16, 32, or 64 bits) while Bignum instances are integers that exceed that sized storage space. The good news for developers is that you don’t have to worry about the size of the integer (see the code sample below). Ruby automatically takes care of any conversion across the Fixnum/Bignum barrier for you!

irb(main):001:0> i=4=> 4irb(main):002:0> i.class=> Fixnumirb(main):003:0> i=i+100000000000000=> 100000000000004irb(main):004:0> i.class=> Bignumirb(main):005:0> i=i-100000000000000=> 4irb(main):006:0> i.class=> Fixnum

Strings
Strings are arbitrary sequence of bytes in Ruby. Usually they are a sequence of characters. In Ruby, instances of the String class can be created using a literal or the new method on the String class.

irb(main):001:0> s1="Hello World"=> "Hello World"irb(main):002:0> s2=String.new("Hello World")=> "Hello World"

Of course, the String defines a great many methods (and operators) for string instances. Also, strings can either be specified with single or double quotes. Double quotes allow for many escape characters and embedded expressions to be evaluated and used in the strings. With single quoted strings, what you see is what you get. For a better understanding, look at the following examples.

irb(main):001:0> str1='a 
 string'=> "a \n string"irb(main):002:0> str2="a 
 string"=> "a 
 string"irb(main):003:0> puts str1a 
 string=> nilirb(main):004:0> puts str2a  string=> nilirb(main):005:0> 'try to add #{2+2}'=> "try to add #{2+2}"irb(main):006:0> "try to add #{2+2}"=> "try to add 4"irb(main):007:0> this="that"=> "that"irb(main):008:0> 'when single quote rights #{this}'=> "when single quote rights #{this}"irb(main):009:0> "double quote rights #{this}"=> "double quote rights that"

Notice how text inside of double quotes is evaluated before displaying where character escapes (like
) and expressions (like #{2+2}) included. On the other hand, these items are treated literally in single quoted strings?

Besides the single and double quote characters to denote a string literal, there is another way to write string literals in Ruby. A percent sign and lowercase or uppercase letter Q can be used to write a string in either single-quote or double-quote style respectively.

irb(main):001:0> %[email protected] is a single quote string #{2+2} [email protected]=> "this is a single quote string #{2+2} here"irb(main):002:0> %[email protected] is a double quote string #{2+2} [email protected]=> "this is a double quote string 4 here"

Note that the character following q% or Q% defines the beginning and end of the string literal. The @ symbol is used in this example as the delimiter marking the beginning and ending of the string.

It should be noted for those that come from other programming language backgrounds that Ruby does not differentiate between a string and character. In other words, there is no special class for single characters, they are just small strings.

Boolean
Lastly, before leaving the “standard” types arena, let’s look at Booleans. In Ruby, there are two classes for Boolean: TrueClass and FalseClass. There is only one instance (a singleton) for each of these classes; namely true and false. These are global values accessible anywhere in Ruby. There is also a class called the NilClass. NilClass also has only one instance?nil. Nil represents…well, nothing. In the case of Boolean logic, however, nil is synonymous with false.

irb(main):001:0> true|false=> trueirb(main):002:0> true&false=> falseirb(main):003:0> true|nil=> trueirb(main):004:0> true&nil=> false

Regular Expressions
Most programming languages utilize regular expressions. Ruby, having descended from many scripting languages, makes extensive use of regular expressions. A co-worker of mine once said “regular expressions aren’t.” Regular that is. In other words, regular expressions can take some effort and time to fully understand. You will only get a glimpse of the power of Ruby’s regular expressions here. You don’t have to use regular expressions to write your applications, but suffice it to say it can make writing applications that work with Strings, in particular, much tighter and easier to write. This section will get you started, but you have some homework to research expressions if you are going to be a Ruby guru.

A regular expression “is a string that describes or matches a set of strings” based on some defined syntax. Another term for regular expression is “pattern.” Regular expressions are used to do string manipulation or searching. You have probably used a regular expression when looking for files on your hard drive. For example, if you want to delete all the files that begin with “ruby” in a particular directory, you might use the rm ruby* command on your Windows or Unix box. In this simple example, ruby* is the regular expression you use to describe or match files.

Regular expressions in Ruby are defined between Tiger or Phil.

/Tiger|Phil/

You can now use this regular expression with a match operator (“=~”) in a conditional or loop statement to match or find other strings.

irb(main):001:0> golfer="Davis"if golfer =~ /Tiger|Phil/	puts "This is going to be a long drive."else	puts "And now a drive by " + golferend=> "Davis"And now a drive by Davis

Here is another regular expression that is a bit more complex: /[w._%-][email protected][w.-]+.[a-zA-Z]{2,4}/. Can you guess what this expression represents? If you guessed an email address, you are right. This regular expression could be used to validate email addresses.

Editor’s Note: A sharp-eyed reader, Sam Livingston-Gray, sent us this alternative regular expression, which is a bit more rigid about validating email addresses. Our thanks to Sam for the suggestion.

     /A[w._%-][email protected][w.-]+.[a-zA-Z]{2,4}z/

irb(main):001:0> emailRE= /[w._%-][email protected][w.-]+.[a-zA-Z]{2,4}/email = "[email protected]"if email =~ emailRE	puts "This is a valid email address."else	puts "this is not a valid email address."endThis is a valid email address.irb(main):002:0>email = "###@spammer&&&.333"if email =~ emailRE	puts "This is a valid email address."else	puts "this is not a valid email address."endthis is not a valid email address.

Figure 2 dissects the email regular expression. As you can see, the regular expression language is quite rich and unfortunately cannot be covered in detail here. For more information, take a look at http://www.regular-expressions.info.

Figure 2. Email Regular Expression: The regular expression to describe email addresses may look complex but it is really just a set of patterns that describe each section of the email address – user, domain and qualifier.

And if you haven’t guessed it by now, regular expressions live up to the Ruby mantra “everything is an object” because regular expressions are objects too. In the code example below, a regular expression instance (from class Regexp) is used as a parameter to a String method, gsub, to replace “happy” and “joy” with “glad.”

irb(main):001:0> quote = "I am so happy. Happy, happy, joy, joy!"regx = /(h|H)appy|joy/quote.gsub(regx, "glad")=> "I am so happy. Happy, happy, joy, joy!"=> /(h|H)appy|joy/=> "I am so glad. glad, glad, glad, glad!"

When you use the =~ operator on the regular expression object, you can get information such as the index of the matching pattern string.

irb(main):001:0> /Tiger|Phil/=~"EyeOfTheTiger"=> 8

The power of regular expression in Ruby becomes pretty apparent if you have ever had to write an application that works heavily with strings. While a bit chewy, you owe it to yourself to fully explore regular expressions in Ruby before you get too deep in coding your first application. Take a look at the sample application attached to this article for more examples of regular expressions in Ruby.

Ranges
A very unusual but useful definition in Ruby is the concept of a range. A range is simply a set of sequential values. For example, the characters a through z define a range inclusive of all the lowercase characters in the English alphabet. Another example is the range of integers 1 through 10. A range can be created from any type of object given the type of object allows comparison using the Ruby comparison operator (<=>) and the succ method. The <=> operator returns -1, 0 or +1 depending on whether the left-hand operand is less than, equal to or greater than the right-hand operand. For example “A”<=>“B” both return -1. The succ method runs on the integer 4 (4.succ) would return 5 and succ run on a returns b.

Ranges can be created using the new method on the Range class or using special notation. Below, two identical ranges for uppercase letters are created in irb using parentheses and dot-dot shorthand notation.

irb(main):001:0> r1=Range.new("A","Z")=> "A".."Z"irb(main):002:0> r2=("A".."Z")=> "A".."Z"

When creating a range, a beginning and ending value must be specified; in this case A as the beginning value and Z as the ending value. When creating a range, you can also signify whether the range should be inclusive or exclusive of the end element. By default, as shown above, the range includes the end value. To exclude the end element from the range, use the exclusive parameter on the new method or triple-dot shorthand notation as shown below.

irb(main):001:0> r1=Range.new("A","Z",true)=> "A"..."Z"irb(main):002:0> r2=("A"..."Z")=> "A"..."Z"irb(main):003:0> r1.include?"Z"=> falseirb(main):004:0> r2.include?"Z"=> false

The include? method called on a range as shown above indicates whether the parameter is a member of the range. In the case shown, “Z” is not an element. There is an operator for this same method. “===” (that’s three equal signs together) performs the same task.

irb(main):005:0> r2==="Z"=≫ false

Ranges are used in many aspects of Ruby programming. In particular, they have two specific uses: as generators and predicates. As a generator, the method each on a range allows you to iterate through each element in the range. For example, say you wanted to determine the number of actual bytes in a range of kilobytes. The code shown run in the irb below uses a range as generator for kilobytes to bytes.

irb(main):008:0> kilobytes=(1..10)kilobytes.each{|x| puts x*1024}=> 1..1010242048307240965120614471688192921610240

In Ruby conditional logic ranges can be used as predicates, usually with the help of the === operator. For example, you could use a range predicates to test an integer reference against valid port numbers (0 through 65535) and reserved ports (0 through 1024 non-inclusive).

irb(main):001:0> proposedPort = 8080validPorts=(0..65535)reservedPorts=(0...1024)if (validPorts === proposedPort) & !(reservedPorts === proposedPort)	puts "Proposed port is ok to use."else	puts "Proposed port is not allowed to be used."end=> 8080=> 0..65535=> 0...1024Proposed port is ok to use.

Ranges are also very useful in accessing elements of data structures like arrays and hashes which is our next topic.

Data Structures
As with many programming languages, Ruby comes complete with built in data structures to contain and manage data and objects. Arrays are objects that hold a collection of other object references. Arrays are created using square bracket notation and separating object references in the list with commas.

presidents=["John","Richard","Gerald","Ronald","George","William"];

To make it easier to construct an array full of words as above, a special notation is provided to eliminate the double quotes and commas.

presidents= %w[ John Richard Gerald Ronald George William];

It other programming languages, the term “array” often implies a homogenous collection of objects. Not so in Ruby. In Ruby, an array can be a heterogeneous collection of object references. So, the following is a perfectly legal array.

order_date=Date.today()shirt_information=[14.5,”Long”,32,order_date]

Object references are stored sequentially and indexed in the array. Like Java, the indexes start at 0 and the index can be used to retrieve the object reference from the array. Below, the third element (at index of 2) is requested from the shirt_information array created above in the irb. Notice you can use either the square bracket notation or the at method to retrieve object references from the array?

irb(main):003:0> shirt_information[2]=> 32irb(main):004:0> shirt_information.at(2)=> 32

Interestingly, you can also reference elements in the array using a “negative index.” A negative index is counted from the end of the array.

irb(main):005:0> shirt_information[-3]=> "Long"

Arrays are dynamic, meaning the size of the array changes dynamically depending on your operations. You can add or replace an element in the array using the [index]= operator.

irb(main):013:0> shirt_information=> [14.5, "Long", 32, #]irb(main):014:0> shirt_information[1]="Medium" #change shirt length=> "Medium"irb(main):015:0> shirt_information[4]=49.99	 #add shirt cost=> 49.99irb(main):016:0> shirt_information=> [14.5, "Medium", 32, #, 49.99]

You can also use number pairs and ranges to create new arrays from portions of the array using a [start index, element count] notation or [beginning_index..ending_index] notation.

irb(main):019:0> shirt_information=> [14.5, "Long", 32, #, 49.99]irb(main):020:0> shirt_dimensions = shirt_information[0,3]=> [14.5, "Long", 32]irb(main):021:0> shirt_order = shirt_information[2..5]=> [32, #, 49.99]irb(main):030:0> shirt_information[-3,2]=> [32, #]

This notation combined with the assignment operator ([ ]=) gives rise to a very intricate element insert or replacement operations. A beginning/ending index or range can be used in the assignment operator. This can be best understood with some example code.

irb(main):001:0> test_array=["zero", "one", "two", "three", "four"]=> ["zero", "one", "two", "three", "four"]irb(main):002:0> #starting at the second element, replace the next two elements with a single elementirb(main):003:0* test_array[1,2]=1=> 1irb(main):004:0> test_array=> ["zero", 1, "three", "four"]irb(main):005:0> #insert a new element after the second element (zero as a second parameter indicates “insert”)irb(main):006:0* test_array[2,0]=2=> 2irb(main):007:0> test_array=> ["zero", 1, 2, "three", "four"]irb(main):008:0> #add an array of elements after element 5irb(main):009:0* test_array[5,0]=[5,6,7]=> [5, 6, 7]irb(main):010:0> test_array=> ["zero", 1, 2, "three", "four", 5, 6, 7]irb(main):011:0> #replace elements in the index range of 3..4 with the array assignedirb(main):012:0* test_array[3..4]=[3,4]=> [3, 4]irb(main):013:0> test_array=> ["zero", 1, 2, 3, 4, 5, 6, 7]

Finally, maybe some of the most powerful operations with Ruby arrays are found in the “mathematical” operators that create new arrays from existing arrays. For example, the + operator allows you to create a new array from two arrays concatenated together and the * operator allows you to duplicate or concatenate an array with itself so many times.

irb(main):033:0> shirt_information=> [14.5, "Long", 32, #, 49.99]irb(main):034:0> pant_information=[34,32,59.99,order_date]=> [34, 32, 59.99, #]irb(main):035:0> shirt_information + pant_information=> [14.5, "Long", 32, #, 49.99, 34, 32, 59.99, #]irb(main):036:0> shirt_information * 2=> [14.5, "Long", 32, #, 49.99, 14.5, "Long", 32, #, 49.99]irb(main):037:0> array1 = [2,4,6,8,10]=> [2, 4, 6, 8, 10]irb(main):038:0> array2=[3,6,9]=> [3, 6, 9]irb(main):039:0> array1 - array2=> [2, 4, 8, 10]

Closely related cousins to Arrays in Ruby are Hashes. The index used to sequence and refer to object references in an array was an integer. The Hash class in Ruby behaves like Array except that it allows any type of object “index” or key to reference objects in the collection. In other programming languages this might be called a dictionary or map or hash map. In general, when working with a hash, you supply two object references for every element in the collection. One object reference is the key and other is what the key points to called the value. The notation used to show what a key object points to is the => symbol. Key/value pairs can be collected between two curly brackets when creating a hash. As an example of a hash, use simple string objects as keys to reference Date objects (values) in a hash.

holidays={"New Year"=>Date.parse("2006-01-02"), "MLB Birthday"=> Date.parse("2006-01-16"), "Washington Birthday"=>Date.parse("2006-02-20"), "Memorial Day"=>Date.parse("2006-05-29"), “July4th”=>Date.parse(“2006-07-05”)}

To retrieve the Date object for Memorial Day, use the “Memorial Day” string key.

irb(main):004:0> holidays["Memorial Day"]=> #irb(main):005:0> holidays["Memorial Day"].to_s=> "2006-05-29"

The statement made earlier that “any” object could be used as a key in a Hash is restricted by the fact that objects that serve as keys must respond to the hash method with a hash value that does not change. The hash value of any object is a fix number created by Ruby to uniquely identify an object. The content of a collection object (like an array or hash) is used to determine its hash code. Because the content of a collection object can change, so too can their hash code change; thus instances of Array and Hash cannot serve as keys in a hash object. While hashes provide the convenience of allowing almost any object to serve as the index or key, their disadvantage is that they are not sequential or ordered as are arrays.

As you might expect, there are many additional methods on the Array and Hash classes that allow you to access and modify individual elements in the collection or change the entire collection itself. As shown here, arrays and hashes in Ruby are very powerful and dynamic data structures.

Once you have a collection of object references, one of the most common tasks in programming is to cycle through or “iterate” through the elements in the collection and perform some task. Ruby, like Java, C#, Lisp, and several other programming languages has a built in mechanism for iterating through the elements in an array or hash. The mechanism Ruby provides to iterate is a set of special methods on the collection objects. Methods like each, each_index, delete_if on Array and each, each_key, each_value, each_pair on Hash allow your code to cycle through and take action on the contents of the collection. In fact, many classes in Ruby contain iterator methods. String, for example provides iterator methods to perform tasks on strings separated by a designated character or by bytes. However, before you can understand iterator methods, you need to understand the concept of code blocks in Ruby. For each of the iterator methods are passed a block of code to execute when iterating over members of the collection.

Code Blocks, Iterators, and Procedure Objects
Everything in Ruby is an object? Just about, yep! Even a chunk of code can be an object! In Ruby, code objects are called code blocks. Think of code blocks as little program suitcases. They contain Ruby code and can travel to methods where they can be executed. Python, C, and Java developers may all find similarities to Ruby code blocks in things like function pointers, anonymous functions, inner classes and callbacks.

The syntax for a Ruby code block is just to put Ruby code between curly braces or do/end commands.

{ 	# this is a code block... }do	# ...and this is a code blockend

In a very simple example, { puts “hello world” } is a valid code block. How do you use these code blocks and pass them as a suitcase of code to a method? For that, first define a very simple method like the one below.

def someMethod	yieldend

The command yield transfer control to the code block that is passed to the method. The code below shows you how a code block is passed to the simple method above using a simple code block.

irb(main):001:0> someMethod {puts "hello world"}hello world

Each time yield is called, the code block passed to the method gets executed. Here is another example of a more complex method using a code block that does a little more work.

irb(main):001:0> def fibonacci (stop)	while stop < 20		stop=yield	endend=> nilirb(main):006:0> i=0; j=1; fibonacci(j) {puts i; temp = i; i = j;j = temp + j}0112358

Code blocks are used throughout Ruby. Most importantly, code blocks are used internally by Ruby in the iterator methods of classes like Array, Hash, and even String. A code block is how you define what task to perform (typically a task on the elements) when iterating through all the elements in an array. To demonstrate code blocks and iterators, a small example is in order. Assuming you had defined a number of barn yard animal classes as those defined in Figure 3 and an Array of those animals, you could make each talk using a code block and an iterator on the array.

irb(main):031:0> barnYard = [Cow.new, Duck.new, Chicken.new, Horse.new, Dog.new]=> [#, #, #, #, #]irb(main):032:0> barnYard.each {|animal| animal.talk}MoooooQuackCluck-cluckNaaaayBark bark 
Figure 3. Simple Ruby Barn Yard Classes: If your barn yard of animals was defined as represented in the Ruby code in this figure, then you could use a code block in a call to each on an array of animals to make them talk as shown below.

The method each called on barnYard is one of the iterator methods for an array. Notice the |) help to define arguments to receive parameters. In this case, the code block receives one argument; namely each successive animal in barnYard as the iterator loops through the collection of animals.

Iterators and code blocks even allow us to do something as simple and neat as the following example:

irb(main):001:0> 3.times {puts "Ruby is cool!"}Ruby is cool!Ruby is cool!Ruby is cool!

That’s right, even the Integer class offers an iterator (the times method) that uses a code block to provide a quick and dirty for-loop.

Before leaving a discussion of code blocks and iterators, you should know that code blocks can be assigned to a variable. In fact, such code blocks are actually instances of the Proc class. You can define a Proc instance using the new method or use the #>Proc:[email protected](irb):1>irb(main):002:0> anotherProc = proc {|str| puts str}=> #>Proc:[email protected](irb):2>

These Proc instances can then be invoked by using the call method.

irb(main):003:0> simpleProc.callhello=> nilirb(main):004:0> anotherProc.call("hello yourself")hello yourself=> nil

This allows a reusable chunk of code to be passed around as an object that can be executed anywhere. Again, a little suitcase of Ruby code ready for travel in the reuse world!

irb(main):001:0> def simpleMethod(aProc)	puts "Is Ruby cool or what?"	aProc.call("Way cool dude!")end=> nilirb(main):005:0> simpleMethod(anotherProc)Is Ruby cool or what?Way cool dude!

Input/Output
Throughout this article and the last Ruby article, you have written Ruby code that has used a number of Ruby standard output methods. The methods of print and puts were often used, but the details were glossed over.

It turns out that these methods, and several others for dealing with input and output, are defined in the Kernel module. The Kernel module is included by the Object class. Therefore, the Kernel’s methods are present in every object. On the output side, Kernel defines print, printf, putc, and class and two subclasses (File and BasicSocket) that allow reading and writing to files and sockets. BasicSocket is part of the socket library and will be discussed later. The File class, which includes the FileTest module, provides a number of methods to work with system files (as its class name implies) and directories (which the name of the class does not imply). The methods used from Kernel to write/read to the standard input/output mechanisms are reused to also write and read from instances of File. Below is a code sample to write some names in a newly created file and the corresponding code to read the names back out of the same file into an array.

customers=%w[Jim Kevin Davin Andrew]outFile = File.new("c:\examples\test\customers.txt", "w")customers.each{|customer| outFile.puts(customer)}outFile.close	inFile= File.new("c:\examples\customers.txt", "r")readCustomers=inFile.readlinesreadCustomers.each{|customer| puts customer}inFile.close

Standard Libraries
Along with Ruby’s rich set of built in classes and modules, Ruby also comes with a number of standard libraries. These libraries are not automatically part of the built in Ruby classes, modules, methods you can take advantage of. You will first have to use the require (or load) keyword at the top of your file to use the classes or modules in the library. I mentioned one of those libraries in the previous section?the socket library, which contains a number of Ruby classes (including BasicSocket) for accessing network services. But there are a whole host of other libraries provided with the Ruby download. Have a look in the lib directory of your Ruby download. In the lib directory, you are looking at the many Ruby libraries available to you and your Ruby applications.

The unfortunate part about the libraries is that there is not a lot of documentation on many of these classes. You will find a list of the standard libraries and their files containing classes and modules at http://www.ruby-doc.org/stdlib/. Even this documentation goes to the length of indicating that:

“What you need to know is that 	bold libraries in the table of contents are well documented, and 	italic libraries are not.”

Alas, this is the current state of Ruby. As you can hopefully tell, Ruby is an incredibly rich and powerful language with built in support (through libraries) for many of the functions we need our applications to do, but documentation is still somewhat limited. The good news is that there are a number of people working to improve Ruby’s documentation and support. A number of Ruby forums have sprouted up and the documentation improves with each new release?a result, no doubt, of its recent rise in attention. However, it can still be one of the somewhat frustrating aspects of the language.

A Real-world Ruby Application
With the Ruby you have learned so far, and armed with the Ruby Standard Libraries, you should be ready to build a real world application. To get you started, I have provided a sample application that uses many of the features discussed in this and the previous article. The application reads a simple text file for a set of stock symbols and number of shares that a person owns and looks up the prices for the stocks on a common financial web site (finance.yahoo.com). After retrieving the stock prices, it calculates the value of the person’s portfolio by calculating the shares times the price found for each stock.

Beyond demonstrating simple Ruby syntax and class/object construction, this simple application makes use of Ruby’s built in Array class and I/O features to get the symbol and share information from a text file. It then uses Ruby Standard Library classes to gain a connection to the financial web site and retrieve an HTML page containing the stock price for each symbol provided. Finally, it makes extensive use of regular expressions and code blocks to locate or screen scrape the stock price out of the HTML returned by the HTTP connection.

Figure 4. Executing the Stock Retrieval Sample Application: After downloading the contents of the zip file to your file system, use a command prompt to go to the Ruby source code directory and type “ruby fetcher.rb” as shown. The results should look something like what are seen in this picture.

To get the application working, download and unzip the contents of this zip file associated with this article onto your file system. It will create an examples2 folder wherever it is unzipped. There are four Ruby code files (.rb files) and one holdings.txt file in the examples2 directory. The fetcher.rb file serves as the kick off code for executing the stock quote retrieval. To run the sample application, bring up a command prompt and use ruby to run fetcher.rb.

The holding.txt file contains example stock symbols and the theoretical number of shares owned. The current contents of the holding.txt file contain symbols for 3M, Wells Fargo, and Pfizer and look like this:

MMM 11WFC 20PFE 5

Feel free to add your own symbols and fictional shares in this file. When you execute the application you should see results that look something like those shown in Figure 4.

Wrap Up
Well, the last article and this article should have you well on your way to successfully exploring and implementing with Ruby. But wait, there is more! Next month, I’ll be back with an exploration of Ruby on Rails?the exciting and easy-to-learn Web framework for Ruby.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

The Latest

your company's audio

4 Areas of Your Company Where Your Audio Really Matters

Your company probably relies on audio more than you realize. Whether you’re creating a spoken text message to a colleague or giving a speech, you want your audio to shine. Otherwise, you could cause avoidable friction points and potentially hurt your brand reputation. For example, let’s say you create a

chrome os developer mode

How to Turn on Chrome OS Developer Mode

Google’s Chrome OS is a popular operating system that is widely used on Chromebooks and other devices. While it is designed to be simple and user-friendly, there are times when users may want to access additional features and functionality. One way to do this is by turning on Chrome OS

homes in the real estate industry

Exploring the Latest Tech Trends Impacting the Real Estate Industry

The real estate industry is changing thanks to the newest technological advancements. These new developments — from blockchain and AI to virtual reality and 3D printing — are poised to change how we buy and sell homes. Real estate brokers, buyers, sellers, wholesale real estate professionals, fix and flippers, and beyond may