Comparison of ruby and python line by line (3/3)
This post is the last part of this comparison. I am going to demonstrate how to develop XML-RPC server and client in Ruby and Python. As I said earlier, I don’t know much about Ruby. Below ruby codes are based on an article in Linux Journal #144. I just tried to develop similar program in Python. There are 2 parts; server and client. Let me start from the server.
- Specify executable
Ruby#!/usr/bin/ruby
Python#!/usr/bin/python
- Import modules
Rubyrequire ’net/http’ require ’rexml/document’ require ’xmlrpc/server’
Pythonimport sys import re import urllib from xml.dom.ext.reader import Sax2 from xml.dom.ext import Print from xml import xpath from SimpleXMLRPCServer import SimpleXMLRPCServer
- Initialize regular expressions
Rubynot_in_collection_re = /class="yourEntryWouldBeHereData"/ix on_shelf_re = /CHECK SHELF/ix checked_out_re = /DUE /ix
Pythonnot_in_collection_re = re.compile(r’class="yourEntryWouldBeHereData"’,re.I) on_shelf_re = re.compile(r’CHECK SHELF’,re.I) checked_out_re = re.compile(r’DUE ’,re.I)
- Declare XML-RPC server
Rubyserver = XMLRPC::Server.new(8080)
Pythonserver = SimpleXMLRPCServer((’’,8080))
- Add an handler
Rubyserver.add_handler(name="atf.books", signature=[’array’,’array’]) do |isbns| output = [] isbns.each do |isbn| isbn_output = {’ISBN’ => isbn} if not isbn.match(/[0-9xX]{10}/) isbn_output[’message’] = "ISBN #{isbn} is invalid." output << isbn_output next end amazon_params = {’Service’ => ’AWSECommerceService’, ’Operation’ => ’ItemLookup’, ’AWSAccessKeyId’ => ’XXXXXXXXXXXXXXXXXXXXXXX’, ’ItemId’ => isbn, ’ResponseGroup’ => ’Medium,OfferFull’, ’MerchantId’ => ’All’}.map{|key,value|"#{key}=#{value}"}.join("&") amazon_response = Net::HTTP.get_response(’webservices.amazon.com’, ’/onca/xml?’ << amazon_params) xml = REXML::Document.new(amazon_response.body) new_price = xml.root.elements["Items/Item/OfferSummary/LowestNewPrice/FormattedPrice"] if new_price.nil? isbn_output[’New’] = "None available" else isbn_output[’New’] = "#{new_price.text}" end used_price = xml.root.elements["Items/Item/OfferSummary/LowestUsedPrice/FormattedPrice"] if used_price.nil? isbn_output[’Used’] = "None available" else isbn_output[’Used’] = "#{used_price.text}" end collectible_price = xml.root.elements["Items/Item/OfferSummary/LowestCollectiblePrice/FormattedPrice"] if collectible_price.nil? isbn_output[’Collectible’] = "None available" else isbn_output[’Collectible’] = "#{collectible_price.text}" end response = Net::HTTP.get_response(’catalog.skokielibrary.info’, "/search~S4/i?SEARCH=#{isbn}") if not_in_collection_re.match(response.body) isbn_output[’Library’] = "Library: Not in the Skokie collection." elsif checked_out_re.match(response.body) isbn_output[’Library’] = "Checked out." elsif on_shelf_re.match(response.body) isbn_output[’Library’] = "On the shelf." else isbn_output[’Library’] = "Unparseable response." end output << isbn_output end output end
Pythondef atf_books(isbns): output = [] for isbn in isbns: isbn_output = {’ISBN’: isbn} if not re.match(r’[0-9xX]{10}’,isbn): isbn_output[’message’] = ’ISBN %s is invalid.’ % isbn output.append(isbn_output) continue amazon_params = { ’Service’: ’AWSECommerceService’, ’Operation’: ’ItemLookup’, ’AWSAccessKeyId’: ’XXXXXXXXXXXXXXXXXXXXXXX’, ’ItemId’: isbn, ’ResponseGroup’: ’Medium,OfferFull’, ’MerchantId’: ’All’, } amazon_response = urllib.urlopen(’http://webservices.amazon.com/onca/xml’,urllib.urlencode(amazon_params)) xml = Sax2.FromXmlStream(amazon_response).documentElement try: new_price = xpath.Evaluate(’Items/Item/OfferSummary/LowestNewPrice/FormattedPrice’,xml)[0] isbn_output[’New’] = new_price.childNodes[0].nodeValue except: isbn_output[’New’] = ’None available’ try: used_price = xpath.Evaluate(’Items/Item/OfferSummary/LowestUsedPrice/FormattedPrice’,xml)[0] isbn_output[’Used’] = used_price.childNodes[0].nodeValue except: isbn_output[’Used’] = ’None available’ try: collectible_price = xpath.Evaluate(’Items/Item/OfferSummary/LowestCollectiblePrice/FormattedPrice’,xml)[0] isbn_output[’Collectible’] = collectible_price.childNodes[0].nodeValue except: isbn_output[’Collectible’] = ’None available’ response = urllib.urlopen(’http://catalog.skokielibrary.info/search~S4/i’,’SEARCH=%s’ % isbn) body = response.read() if not_in_collection_re.search(body): isbn_output[’Library’] = ’Library: Not in the Skokie collection.’ elif checked_out_re.search(body): isbn_output[’Library’] = ’Checked out.’ elif on_shelf_re.search(body): isbn_output[’Library’] = ’On the shelf.’ else: isbn_output[’Library’] = ’Unparseable response’ output.append(isbn_output) return output server.register_function(atf_books,’atf.books’)
- Serve clients
Rubyserver.serve
Pythonserver.serve_forever()
You might notice a big difference in the 5th step. Ruby allows to write in-line function very easy. To do the same in Python, the procedure must be written in lambda form. I don’t want to use lambda to implement very long code like thist. Instead, I decided to wrap the routine in a function. And again in 6th step, you might find that a method was called without (). I think this is very confusing feature. How can I know the statement is just to refer to the method or to call the method. Then below is the client.
- Specify executable
Ruby#!/usr/bin/ruby
Python#!/usr/bin/python
- Import modules
Rubyrequire ’xmlrpc/client’
Pythonimport sys from xmlrpclib import ServerProxy
- Initialize arguments
Rubyisbns = ARGV
Pythonisbns = sys.argv[1:]
- Declare XML-RPC client
Rubyserver = XMLRPC::Client.new2("http://127.0.0.1:8080/",nil,120)
Pythonserver = ServerProxy(’http://127.0.0.1:8080’)
- Call a method
Rubybegin results = server.call("atf.books",isbns) rescue XMLRPC::FaultException => e puts "Error:" puts e.faultCode puts e.faultString end
Pythontry: results = server.atf.books(isbns) except Exception,why: print why sys.exit()
- Loop through the results
Rubyresults.each do |result| result.each do |key,value| if key == ’ISBN’: puts "ISBN: #{value}\n" else puts "\t#{key}: #{value}\n" end end end
Pythonfor result in results: print ’ISBN: %s’ % result[’ISBN’] for key,value in result.items(): if key != ’ISBN’: print ’\t%s: %s’ % (key,value)
Can you notice significant difference between Ruby and Python? Ruby’s hash does preserve order but Python doesn’t. So I have to change some logic in the 6th step to show reasonable output.
Don’t forget to read part 1, 2, 3.
Technorati Tags: English, IT, Programming, Python, Tips and Tricks, Ruby, XML-RPC, Web Services
- sugree's blog
- 1642 reads
Post new comment