Wednesday, March 21, 2007

Web Services Made Easy with Ruby

It's easy to develop Web services using Ruby. This article looks at how to develop a Web service client to access the Web services that are hosted in the Internet and how to develop a Web service with simple steps using Ruby.

An Overview
Ruby is the interpreted scripting language invented by Yukihiro Matsumoto for quick and easy object-oriented programming and is more popular in Japan than in other countries. Ruby's open-source nature makes it free for anyone to use. All data structures in Ruby are objects, but you can add methods to a class or instance of a class during runtime. Because of this, any instance class can behave differently from other instances of the same class. Ruby's dynamic typing nature doesn't require explicit declaration of variable types. It features a true mark-and-sweep garbage collector that cleans all Ruby objects without needing to maintain a reference count. (See www.ruby-lang.org for the complete features of Ruby.) The following libraries are developed with Ruby:
# Ruby/DBI: To access different databases
# Ruby/LDAP: To search and operate on entries in the LDAP
# XSLT4R: For XSL transformation
# XMLRPC4R: For writing and accessing Web services
# SOAP4R: For writing and accessing Web services

SOAP Programming Using Ruby
SOAP4R is the implementation of Simple Object Access Protocol for Ruby developed by Hiroshi Nakamura. SOAP4R depends on the XML processor, http-access, logging, and date-time packages. (To install SOAP4R and its dependencies refer to its home page at www.jin.gr.jp/~nahi/Ruby/SOAP4R.)

Develop SOAP4R clients
The SOAP::Driver class provides support for writing SOAP client applications using Ruby. I'll explain how to use this class in order to develop the SOAP client. To invoke a SOAP Service the client should know the URL of the SOAP Service, namespace of the service methods, and the names of the service methods and their parameters. With this information let's develop a SOAP client in Ruby.

I've chosen a "SendEmail" Web service that is listed in Xmethods' Web services list. The client we're developing invokes a service named SendEmail to send an e-mail message to any mail address (see Listing 1).

In the first line I load the feature "soap/ driver", which implements the SOAP::Driver class. Then I define four constants like NAMESPACE, URL, SOAPACTION, and HTTP_ PROXY, which are required to create an instance of SOAP::Driver class by calling its new method.

driver = SOAP::Driver.new(log, logId, namespace ,
endpoint, httpProxy, soapAction )
Where
namespace = namespace to use for RPC calls
endpoint = URL of the SOAP service
httpproxy = to specify the proxy server,
instead of direct connection to SOAP server
soapaction = value for SOAPAction field of the SOAP Header

After creating an instance of the driver class, call the addMethod method passing the name of the SOAP service method and its parameters' names. SOAP method parameters are often not taken into account on the SOAP server side but it is important to know the order of the parameters that were passed to the service.

The SOAP::Driver class has two methods to add service methods:

SOAP::Driver.addMethod(name, *paramArg)
SOAP::Driver.addMethodWithSOAPAction(name, soapaction, *paramArg)
Where name = the name of the remote procedure
soapaction = soap action header to be used instead
of the default one specified on SOAPDrivers newmethod
paramArg = to specify the names and modes of the remote
procedures parameters. The parameter modes are input parameter,
output parameter or in out parameter.

After adding the service method to the Driver class, invoke it by passing the parameters with values.

SOAPDriver::ServiceMethod( *paramvaluesArg)

Where ServiceMethod is the name of the remote procedure, that was added using addMethod API.

The Web services client is now ready for testing. Test the client using the following command:

ruby SendEmail.rb

Just three steps are needed to develop a Web services client using SOAP4R.

Develop SOAP4R Services
SOAP4R supports the following servers:
# CGI/Fast CGI-based servers (SOAP::CGI Stub)
# Stand-alone server (SOAP::Standalone Server)

Now let's look at how to develop services using the stand-alone server. I'll develop a temperature conversion service that converts the temperature from Celsius to Fahrenheit (see Listing 2).

Develop a class called Temperature_ Conversion_Server and inherit from SOAP:: StandaloneServer, which inherits from SOAP:Server.

class Temperature_Conversion_Server
< SOAP::StandaloneServer
# declare methods
# define methods
end

Declare your service methods by overriding the methodDef method in the StandaloneServer. For example, convert_to_ Fahrenheit, which takes degrees as input parameters:

def methodDef addMethod(self,
'convert_to_Fahrenheit', 'degrees' )
end

The methodDef method is implicitly called from SOAP::Server's initialize method, which exposes one of the following two ser-vice methods.

Class Server < Devel::Application
def addMethod( receiver, methodName, *paramArg )
end

def addMethodWithNS( namespace, receiver, methodName, *paramArg )
end
end
Where
Receiver = the object which contains the methodName method.
Use "self" if the service method is in the same class
methodName = the name of the method that is called through an RPC request
paramArg = to specify the parameter names and parameter modes
namespace = in order to specify the namespace for the method.
Use this if you want different namespace for each method.

After you declare the service method, define it as:

def convert_to_Fahrenheit( degrees )
temp = (9*degrees + 160)/5
return temp
end

The StandaloneServer constructor looks like:

class StandaloneServer < Server
def initialize( appName, namespace, host = "127.0.0.1", port = 8080 )
end
appName - to specify the applications log Id paramters
namespace - Namespace parameters apply to default namespace
for all the service methods.app host to specify the server
host by default it is local host i.e "127.0.0.1",
port to specify the port number for the server ,
by default it is 8080.

Create an instance of the StandaloneServer class and start the server:

myServer = Temperature_Conversion_Server.new('ConversionServer',
'urn:ruby:conversionservice', 'localhost', 8080)
myServer.start

The temperature conversion service is now ready for testing. Start the server using the following command:

ruby ConversionServer.rb

Develop a Web service client application to test the Temperature conversion service (see Listing 3) and test the service using the command:

ruby ConversionClient.rb

In order to monitor the Web service traffic (i.e, SOAP Request and SOAP Response), run the monitor application, which is included with the XML-RPC samples.

Conclusion
It's easy to develop Web services with Ruby. SOAP4R supports logging for the client side and server side as well and supports the user-defined data types. SOAP4R provides the ability to customize the mapping between the Ruby and the SOAP Types. It has good support for SOAP Parameters like IN, OUT, INOUT, and return, and supports WSDL as well. Refer to the samples that come with SOAP4R for more information.

References
# Ruby: www.ruby-lang.org/en/
# SOAP4R: www.jin.gr.jp/~nahi/Ruby/SOAP4R

The Philosophy of Ruby

Summary

Yukihiro Matsumoto, the creator of the Ruby programming language, talks with Bill Venners about Ruby's design philosophy, including design imperfection, the danger of orthogonality, and the importance of the human in computer endeavors.

Yukihiro Matsumoto, or "Matz," as he is known online, is the creator of the Ruby programming language. Ruby is an object-oriented language suitable for writing day to day scripts as well as full-scale applications. Matz began work on Ruby back in 1993, because he wanted a language that made him productive while being fun to use. Initially popular in Japan, Ruby has been finding its way into the hearts of programmers all over the world.

On September 24, 2003, Bill Venners met with Yukihiro Matsumoto at the JAOO conference in Aarhus, Denmark. In this interview, which will be published in multiple installments on Artima.com, Yukihiro Matsumoto discusses Ruby's design philosopy, the features of the Ruby language, and becoming a better programmer. In this initial installment, Matz waxes philosophic about design imperfection, the danger of orthogonality, granting freedom with guidance, the principle of least surprise, and the importance of the human in computer endeavors.

No Perfect Language

Bill Venners: Dave Thomas, coauthor of Programming Ruby: A Pragmatic Programmer's Guide, told me that you don't think a language design should be perfect. Why not?

Yukihiro Matsumoto: Language designers want to design the perfect language. They want to be able to say, "My language is perfect. It can do everything." But it's just plain impossible to design a perfect language, because there are two ways to look at a language. One way is by looking at what can be done with that language. The other is by looking at how we feel using that language—how we feel while programming.

Because of the Turing completeness theory, everything one Turing-complete language can do can theoretically be done by another Turing-complete language, but at a different cost. You can do everything in assembler, but no one wants to program in assembler anymore. From the viewpoint of what you can do, therefore, languages do differ—but the differences are limited. For example, Python and Ruby provide almost the same power to the programmer.

Instead of emphasizing the what, I want to emphasize the how part: how we feel while programming. That's Ruby's main difference from other language designs. I emphasize the feeling, in particular, how I feel using Ruby. I didn't work hard to make Ruby perfect for everyone, because you feel differently from me. No language can be perfect for everyone. I tried to make Ruby perfect for me, but maybe it's not perfect for you. The perfect language for Guido van Rossum is probably Python.

Orthogonal versus Harmonious

Bill Venners: Dave Thomas also claimed that if I ask you to add a feature that is orthogonal, you won't do it. What you want is something that's harmonious. What does that mean?

Yukihiro Matsumoto: I believe consistency and orthogonality are tools of design, not the primary goal in design.

Bill Venners: What does orthogonality mean in this context?

Yukihiro Matsumoto: An example of orthogonality is allowing any combination of small features or syntax. For example, C++ supports both default parameter values for functions and overloading of function names based on parameters. Both are good features to have in a language, but because they are orthogonal, you can apply both at the same time. The compiler knows how to apply both at the same time. If it's ambiguous, the compiler will flag an error. But if I look at the code, I need to apply the rule with my brain too. I need to guess how the compiler works. If I'm right, and I'm smart enough, it's no problem. But if I'm not smart enough, and I'm really not, it causes confusion. The result will be unexpected for an ordinary person. This is an example of how orthogonality is bad.

Bill Venners: In other words, the orthogonal features will work once the compiler writer understands them and gets them to work. But it is hard for programmers to understand it when they look at it, because it is complicated, because I have to figure out how these two things go together.

Yukihiro Matsumoto: The orthogonal features, when combined, can explode into complexity.

Bill Venners: So what's the alternative? What would be more harmonious?

Yukihiro Matsumoto: Just pick up one of those two to put into the language. You don't have to do everything that you can think of. You need to pick one of them, even though both are good.

Freedom and Comfort

Bill Venners: One of the design philosophies in the Python community is providing one and only one way to do things. If you provide fifty different ways to do the same thing, then you've provided convenience for code writers. People can write things in their favorite way. The tradeoff is for code readers. When I read your code, you might have written it one way. When I read the next person's code, they may have written it another way. So as a reader I end up needing to be familiar with all ways to accomplish the task, not just my favorite way of writing it. That's the design tradeoff. The Python community seems to prefer the one and only one way approach, but Ruby seems to provide multiple ways to do the same thing.

Yukihiro Matsumoto: Ruby inherited the Perl philosophy of having more than one way to do the same thing. I inherited that philosophy from Larry Wall, who is my hero actually. I want to make Ruby users free. I want to give them the freedom to choose. People are different. People choose different criteria. But if there is a better way among many alternatives, I want to encourage that way by making it comfortable. So that's what I've tried to do. Maybe Python code is a bit more readable. Everyone can write the same style of Python code, so it can be easier to read, maybe. But the difference from one person to the next is so big, providing only one way is little help even if you're using Python, I think. I'd rather provide many ways if it's possible, but encourage or guide users to choose a better way if it's possible.

The Joy of Ruby

Bill Venners: In an introductory article on Ruby, you wrote, "For me the purpose of life is partly to have joy. Programmers often feel joy when they can concentrate on the creative side of programming, So Ruby is designed to make programmers happy." How can Ruby make programmers happy?

Yukihiro Matsumoto: You want to enjoy life, don't you? If you get your job done quickly and your job is fun, that's good isn't it? That's the purpose of life, partly. Your life is better.

I want to solve problems I meet in the daily life by using computers, so I need to write programs. By using Ruby, I want to concentrate the things I do, not the magical rules of the language, like starting with public void something something something to say, "print hello world." I just want to say, "print this!" I don't want all the surrounding magic keywords. I just want to concentrate on the task. That's the basic idea. So I have tried to make Ruby code concise and succinct.

Bill Venners: Allowing programmers to write code that's concise and succinct is one way to make them happy.

Yukihiro Matsumoto: Yes, so they can concentrate on the problem itself. Sometimes people jot down pseudo-code on paper. If that pseudo-code runs directly on their computers, it's best, isn't it? Ruby tries to be like that, like pseudo-code that runs. Python people say that too.

Bill Venners: Yes, Python people do say that Python is executable pseudo-code. What else is in Ruby to make programmers happy?

Yukihiro Matsumoto: In our daily lives as programmers, we process text strings a lot. So I tried to work hard on text processing, namely the string class and regular expressions. Regular expressions are built into the language and are very tuned up for use. We also need to call into the operating system a lot. Ruby can call every system call in Unix and most of the Windows API. This brings the power and function of the operating system to the interpretive language environment. So you can do daily systems administration and text processing programming. That's the major domain of at least my life, so I worked hard on making that good.

Bill Venners: So basically Ruby helps me enjoy my life by helping me get my job done more quickly and with more fun?

Yukihiro Matsumoto: It helps me do that. I'm not sure Ruby works for you, but I hope so.

The Human Factor

Bill Venners: In an interview, you said, "Don't underestimate the human factor. Even thought we are in front of computers, they are media. We are working for human, with human." What do you mean by that?

Yukihiro Matsumoto: Imagine you are writing an email. You are in front of the computer. You are operating the computer, clicking a mouse and typing on a keyboard, but the message will be sent to a human over the internet. So you are working before the computer, but with a human behind the computer. Most of the tasks we do are for humans. For example, a tax calculation is counting numbers so the government can pull money out from my wallet, but government consists of humans.

Most of our tasks are related to humans after all. So in programming, either we ask the computer to work for a human, or we describe our thoughts to a computer in a very unambiguous way that even computer can execute. In the first case, making the computer work for humans, the target is a human through the computer. In the second case, expressing our thoughts clearly enough to be understood and executed by computers, we express intent from our human brains and as a result it is performed by the computers. So in both cases the object here is human.

Bill Venners: What is important about thinking that way? You say, "Don't underestimate the human factor." Why?

Yukihiro Matsumoto: Because computers don't mind if I must make effort to communicate with them or if it is easy to communicate with them. They don't care if I put the numbers of instruction byte sequences in a file and feed it to them to run, or if a very high level language generated the instructions. The computers don't care. We humans care about the effort we pay. Often people, especially computer engineers, focus on the machines. They think, "By doing this, the machine will run faster. By doing this, the machine will run more effectively. By doing this, the machine will something something something." They are focusing on machines. But in fact we need to focus on humans, on how humans care about doing programming or operating the application of the machines. We are the masters. They are the slaves.

Bill Venners: For the time being anyway.

Yukihiro Matsumoto: For the time being anyway, until the age of Terminator.

Principle of Least Surprise

Bill Venners: In an interview, you said "I designed Ruby to minimize my surprise. I was very amazed when people around the world told me that Ruby reduced their surprise and enhanced their joy of programming. Now I'm pretty sure that programmer's minds are alike all over the world." Why the principle of least surprise?

Yukihiro Matsumoto: Actually, I didn't make the claim that Ruby follows the principle of least surprise. Someone felt the design of Ruby follows that philosophy, so they started saying that. I didn't bring that up, actually.

I wanted to minimize my frustration during programming, so I want to minimize my effort in programming. That was my primary goal in designing Ruby. I want to have fun in programming myself. After releasing Ruby and many people around the world got to know Ruby, they said they feel the way I feel. They came up with the phrase the principle of least surprise. But actually, it's often misunderstood.

Bill Venners: How is it misunderstood?

Yukihiro Matsumoto: Everyone has an individual background. Someone may come from Python, someone else may come from Perl, and they may be surprised by different aspects of the language. Then they come up to me and say, "I was surprised by this feature of the language, so therefore Ruby violates the principle of least surprise." Wait. Wait. The principle of least surprise is not for you only. The principle of least surprise means principle of least my surprise. And it means the principle of least surprise after you learn Ruby very well. For example, I was a C++ programmer before I started designing Ruby. I programmed in C++ exclusively for two or three years. And after two years of C++ programming, it still surprised me.