One of my duties at work is maintaining and extending our Intranet site, which is written in classic ASP and VBScript. I consider this an unfortunate situation, because I don't like ASP or VBScript. Or IIS, or Windows for that matter. But there it is.
Recently I fed a troll on Slashdot in a thread about ASP and PHP. Another comment on the same thread mentions that you can use other languages than VBScript and JScript in ASP pages if you want - he mentions Ruby, Python, and Perl, and PHP and Lua are available as well. That reminded me that this was something I always wanted to look into. So I installed Python, Ruby, PHP, and Perl. I haven't gotten PHP working in IIS yet, but the others work quite well.
I wrote some simple pages to test each language, and then I started experimenting more with Ruby. It takes some getting used to to program in this environment; you have to remember to use Response.Write instead of puts, for instance. The script's working directory is c:\windows\system32 instead of where the page actually lives. But it's incredibly nice to have Ruby's large class library and syntactic sugar. You have the choice of doing things through OLE (i.e. Server.CreateObject("Microsoft.XMLHTTP")) or through native Ruby (i.e. Net::HTTP.get(…)).
It gets complicated when you're trying to convert properties from the ASP built-in objects (Request, Response, Server, etc.) to Ruby objects. Everything provided by ASP is a WIN32OLE object in Ruby. So, unless I'm missing something, I'm going to have to deal with converting whatever I need from ASP to Ruby before I can use it.
An example: I said before that the initial working directory of the Ruby script (Dir.getwd) is c:\windows\system32, I guess because that's where the DLL lives. In ASP, you can get the directory the script is in from Request.ServerVariables("APPL_PHYSICAL_PATH"). But you can't do Dir.chdir(Request.ServerVariables("APPL_PHYSICAL_PATH")) because that property is a WIN32OLE object, not a string. And its to_s method just returns its instance.
In fact, none of the methods you can call on that object return its value, and although you can iterate with Request.ServerVariables.each, all you get are the names of the items in the collection, not their values.
It took some experimenting, but eventually I figured out a way to get to the value. I was thinking of it like a hash, but ServerVariables is sort of a collection of collections. Each collection in the collection has one item in it: a Ruby string containing the value of the variable. But a hash would be easier to work with, so I wrote a mixin to return a hash representation of ServerVariables:
<%@language="RubyScript"%>
<%
module W32Helpers
def to_hash
if not is_a? WIN32OLE then return nil end
hash = Hash.new
each do |key|
value = nil
Item(key).each do |member|
value = member
break
end
hash[key] = value
end
hash
end
end
sv = Request.ServerVariables
sv.extend(W32Helpers)
Dir.chdir(sv.to_hash['APPL_PHYSICAL_PATH'])
Response.Write Dir.getwd # sweet.
%>
This should work on any WIN32OLE object that is Enumerable. I imagine there's a way to check if that's the case, but I havent found it yet. And it's only one-dimensional. An interesting aside: chdir appears to be application-wide and persistent across sessions.
I'm sure there'll be other ways to improve the Ruby/ASP environment. Maybe I'll work out a way to load some modules at the beginning of a script and set everything up beforehand. Should be good.