Need Ruby? Nah--get Monad instead

I happened across this blog entry while doing some research on Monad, Microsoft's new command shell (meaning, think "bash" or "csh", not "Explorer"), and found it so similar in many ways to what guys in the Ruby space have been hyping for a year or two now, that I just had to pass it on. Reproducing directly from the site:

One of the scripts I like the most in my toolbox is the one that gives me answers to questions from the command line.

For the past 2 years or so, Encarta has offered an extremely useful Instant Answers feature. Its since been integrated into MSN Search, as well as a wildly popular Chat Bot. MoW showed how to use that feature through a Monad IM interface (via the Conversagent bot,) but we can do a great job with good ol screen scraping.

[C:\temp]
MSH:70 > get-answer "What is the population of China?"

Answer: China: Population, total: 1,313,973,700
2006 estimate
United States Census International Programs Center


Answer: China : Population:
More than 20 percent of the worldâ?Ts population lives in China. Of the co
untryâ?Ts inhabitants, 92 percent are ethnic Han Chinese. The Han are desc
endants...

[C:\temp]
MSH:71 > get-answer "5^(e^(x^2))=50"

Answer: 5^(e ^( x^2))=50 = x=0.942428  x=-0.942428

[C:\temp]
MSH:72 > get-answer "define: canadian bacon"

Definition: Canadian bacon lean bacon

[C:\temp]
MSH:73 > get-answer "How many calories in an Apple?"

Answer: Apples: calories:
1.0 cup, quartered or chopped has 65 calories 1.0 NLEA serving has 80 calo
ries 1.0 small (2-1/2" dia) (approx 4 per lb) has 55 calories 1.0 medium (
2-3/4" dia) (approx 3 per lb) has 72 calories 1.0 large (3-1/4" dia) (appr
ox 2 per lb) has 110 calories 1.0 cup slices has 57 calories
USDA

[C:\temp]
MSH:74 > get-answer "How many inches in a light year?"

Answer: 1 lightyear = 372,461,748,226,857,000 inches
Here is the script, should you require your own command-line oracle:
## Get-Answer.msh 
## Use Encarta's Instant Answers to answer your question. 

param([string] $question = $(throw "Please ask a question.")) 

function Main 
{ 
   # Load the System.Web.HttpUtility DLL, to let us URLEncode 
   [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Web") 

   ## Get the web page into a single string 
   $encoded = [System.Web.HttpUtility]::UrlEncode($question) 
   $text = get-webpage "http://search.msn.com/encarta/results.aspx?q=$encoded" 

   ## Get the answer with annotations 
   $startIndex = $text.IndexOf('<div id="results">') 
   $endIndex = $text.IndexOf('</div></div><h2>Results</h2>') 

   ## If we found a result, then filter the result 
   if(($startIndex -ge 0) -and ($endIndex -ge 0)) 
   { 
      $partialText = $text.Substring($startIndex, $endIndex - $startIndex) 
    
      ## Very fragile, voodoo screen scraping here 
      $regex = "<\s*a\s*[^>]*?href\s*=\s*[`"']*[^`"'>]+[^>]*>.*?</a>" 
      $partialText = [Regex]::Replace("$partialText", $regex, "") 
      $partialText = $partialText -replace "</div>", "`n" 
      $partialText = $partialText -replace "</span>", "`n" 
      $partialText = clean-html $partialText 
      $partialText = $partialText -replace "`n`n", "`n" 
     
      "" 
      $partialText.TrimEnd() 
   } 
   else 
   { 
      "" 
      "No answer found." 
   } 
} 

## Get a web page
function Get-WebPage ($url=$(throw "need to specify the URL to fetch")) 
{ 
    # canonicalize the url 
    if ($url -notmatch "^[a-z]+://") { $url = "http://$url" } 
     
    $wc = new-object System.Net.WebClient  
    $wc.Headers.Add("user-agent", $userAgent) 
    $wc.DownloadString($url) 
} 

## Clean HTML from a text chunk 
function Clean-Html ($htmlInput) 
{ 
    [Regex]::Replace($htmlInput, "<[^>]*>", "") 
} 

. Main

That’s nifty stuff, if you ask me. And, what’s best, this is a loosely-typed, dynamic language every bit as interesting and powerful as Ruby, though admittedly without some of the metaprogramming capabilities that Ruby has. But notice how we’re making use of the vast power underneath the .NET framework to lay out a pretty straightforward use of the code, in a way that’s entirely dynamic and loosely-typed, including the assumed return value from the if/else block, and so on. It’s going to be a whole new world for automating projects (among other things) once Monad ships, and the saavy .NET developer (and even the saavy Java developer who builds on Windows) will already be looking at Monad for ways to streamline the things they need to do on Windows.

Added to my list of developer interview questions: "What is Monad, and why do I care?"