]> gitweb.michael.orlitzky.com - dead/whatever-dl.git/commitdiff
Added the Infoq site.
authorMichael Orlitzky <michael@orlitzky.com>
Mon, 16 Jun 2008 03:43:00 +0000 (23:43 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Mon, 16 Jun 2008 03:43:00 +0000 (23:43 -0400)
Added support for infoq.com by adding a new website class. Infoq
attempts to obscure their video URLs with Base64 encoding which is
easy enough to get around. I implemented this, and a couple of tests
for the new class.

src/websites/infoq.rb [new file with mode: 0644]
test/fixtures/infoq/jim-weirich-discusses-rake.html [new file with mode: 0644]
test/infoq_remote_test.rb [new file with mode: 0644]
test/infoq_test.rb [new file with mode: 0644]
test/remote_test_suite.rb
test/test_suite.rb

diff --git a/src/websites/infoq.rb b/src/websites/infoq.rb
new file mode 100644 (file)
index 0000000..fe05562
--- /dev/null
@@ -0,0 +1,69 @@
+#
+# Copyright Michael Orlitzky
+#
+# http://michael.orlitzky.com/
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# http://www.fsf.org/licensing/licenses/gpl.html
+#
+
+require 'src/website'
+require 'base64'
+
+class Infoq < Website
+
+  VALID_INFOQ_URL_REGEX = /^(http:\/\/)?(www\.)?infoq\.com\/(.+)$/
+
+  def self.owns_url?(url)
+    return url =~ VALID_INFOQ_URL_REGEX
+  end
+
+  
+  def get_video_url(url)
+    page_data = self.get_page_data(url)
+    video_url = self.parse_video_url(page_data)
+    return video_url
+  end
+
+  
+  protected;
+
+  # Get the FLV file URL from the HTML page for this movie.
+  # It's encoded in base64 -- no big deal.
+  def parse_video_url(page_data)
+    # Get the base64 string. It's stored in a javascript
+    # variable called "jsclassref". This regex should match
+    # a javascript variable declaration preceded, separated,
+    # and/or terminated by zero or more whitespace characters.
+    base64_regex = /^\s*var\s+jsclassref=\'(.*)\';\s*$/
+    matches = base64_regex.match(page_data)
+
+    if (matches.nil? || matches.length < 2)
+      raise StandardError.new('There were no base64-encoded video URLs found on the page: ');
+    end
+    
+    return Base64.decode64(matches[1])
+  end
+
+
+  # Just make a normal HTTP "get" request.
+  def get_page_data(url)
+    uri = URI.parse(url)
+    
+    response = Net::HTTP.start(uri.host, uri.port) do |http|
+      http.get(uri.path)
+    end
+    
+    return response.body
+  end
+
+end
diff --git a/test/fixtures/infoq/jim-weirich-discusses-rake.html b/test/fixtures/infoq/jim-weirich-discusses-rake.html
new file mode 100644 (file)
index 0000000..4672bb0
--- /dev/null
@@ -0,0 +1,964 @@
+<html>​​​​​<head><title>InfoQ: Jim Weirich Discusses Rake, the Ruby Make Tool</title>
+
+
+
+
+
+
+
+
+
+
+
+       
+    
+       
+       <meta http-equiv="pragma" content="no-cache">
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="expires" content="0">
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<meta name="copyright" content="© 2006 C4Media">
+<meta name="author" content="alex[at]c4media[dot]com">
+
+       
+       
+    <link rel="stylesheet" type="text/css" media="screen" href="/styles/style.css">
+    <link rel="stylesheet" type="text/css" media="print" href="/styles/print.css"><!--[if IE]>\r
+    <link rel="stylesheet" type="text/css" media="screen" href="/styles/style-ie.css" />\r
+    <![endif]-->
+    
+    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+    
+    <script src="/scripts/JSResource_en.js" type="text/javascript"></script>
+       <script src="/scripts/commons.js" type="text/javascript"></script>
+       <script src="/scripts/ContentSummary.js" type="text/javascript"></script>
+       <script src="/scripts/CategoryManagement.js" type="text/javascript"></script>
+       <script src="/dwr/engine.js" type="text/javascript"></script>
+       <script src="/dwr/util.js" type="text/javascript"></script>
+       <script src="/dwr/interface/UserCategoryUtil.js" type="text/javascript"></script>
+       <script src="/dwr/interface/DWRRewriteAction.js" type="text/javascript"></script>
+       
+
+       
+       <meta name="keywords" content="jim weirich discusses rake,Ruby,Domain Specific Languages,Build systems,Rake,Mocks,">
+       <meta name="description" content="Jim Weirich, is the Chief Scientist for EdgeCase LLC and thecreator of rake, the popular make-like build tool written in Ruby. In this interview with InfoQ, Jim disccusses the birth of rake, Domain Specific Languages, and flexmock, his mocking library.">
+       
+       <script type="text/javascript" src="/scripts/flashdetect.js"></script>
+       <script type="text/javascript" src="/scripts/scrubber/FABridge.js"></script>
+       <script type="text/javascript" src="/scripts/scrubber/FLVScrubberInterview.js"></script></head><body onload="init()"> 
+
+
+
+
+
+<script src="/scripts/prototype.js" type="text/javascript"></script>
+<script src="/scripts/login.js" type="text/javascript"></script>
+<script type="text/javascript">
+var loginLanguage='en';
+var loginURL='/login.action';
+var registerURL='/reginit.action';
+var reactivateURL='/reactivate.action';
+var reserpasswordURL='/resetpassword.action';
+var loggedIn=false;
+var logoutURL='/logout.action';
+var editUserURL='/edituser.action';
+var aboutURL='/about.jsp';
+var homeURL='/';
+</script>
+<div id="tooltip" style="display: none;"></div>
+<div id="loginWindow" style="display: none;"></div>
+<div id="tagPopup" style="display: none;"></div>
+<div id="container">
+       <h1 class="logo"><a style="" href="#">InfoQ</a></h1>
+
+       
+
+
+
+
+
+
+
+<div id="header">
+       <p class="skip"><a style="" href="#content">Skip to Content</a></p>
+
+       <div id="quote"><p>Tracking change and innovation in the enterprise software development community</p></div>
+
+       <div style="margin: 0pt 0pt 2px; padding: 0pt; float: left; width: 29%; position: relative;">
+               <p style="margin: 0pt; padding: 6px 37px 0pt 0pt; float: right;">               
+                       
+
+
+
+
+
+
+En | <a href="/cn/">中文</a> | <a href="/jp/">日本語</a>
+               
+               </p>
+               <p style="margin: 0pt; padding: 6px 9px; text-align: left;">
+            <a href="/articles/InfoQ-Changelog" style="text-decoration: none; color: black;">Version 1.4</a>
+               </p>
+       </div>
+</div>
+
+       
+       
+       <div id="sidebar">
+       <div id="sidebar-wrapper">
+               
+
+
+
+
+<div class="s-logo">
+       
+       <p class="r-logo"><a href="/">InfoQ</a></p>
+</div>
+
+
+               
+               
+
+
+
+
+
+
+
+
+
+
+
+<span style="font-size: x-small;">
+
+    
+    
+320,944 May unique visitors
+</span>
+
+
+                   
+               
+               
+
+
+
+
+
+
+       <div class="box-simple">
+               <div class="box-simple-top"></div>
+               <div id="mainLoginArea" class="box-simple-content">
+                       
+                       
+                       <ul>
+                   <li><a href="/reginit.action">Register</a></li>
+                           <li><a href="javascript:void(0)" onclick="javascript:showLoginWindow(this,ALIGN_LEFT,new Function('void(0);'));">Login</a></li>
+                   <li><a href="/about.jsp">About us</a></li>
+                   
+                   
+                               
+                                       
+                               
+                           <li><a href="/rss/rss.action?token=JjnFl96mlUojLN35SZV6ruxkzcQU26Qx">Personal feed <img src="/styles/i/btn-rss-blue.gif" alt="RSS Feed"></a></li>
+                               
+                           <li><a href="/">Home</a></li>
+                       </ul>
+                       
+               </div>
+               <div class="box-simple-bottom"></div>
+       </div>
+
+
+               
+
+
+
+
+
+
+<div id="mainCommunitiesArea" class="box">
+    <h2>Your Communities</h2>
+    <div class="top-corners"><div></div></div>
+    <div class="box-content">
+    <div class="box-content-2">
+       
+
+
+
+
+<script language="JavaScript">
+var communityChangeMessage = 'Your new preferences will be used starting with the next refresh.';
+</script>      
+
+<div id="communities">
+    <ul>
+       
+               <li><input name="java" value="true" checked="checked" id="community1" onclick="includeExcludeCommunity(this);" type="checkbox">
+ <a href="/java/">Java</a></li>
+       
+               <li><input name="dotnet" value="true" checked="checked" id="community4" onclick="includeExcludeCommunity(this);" type="checkbox">
+ <a href="/dotnet/">.NET</a></li>
+       
+               <li><input name="ruby" value="true" checked="checked" id="community5" onclick="includeExcludeCommunity(this);" type="checkbox">
+ <a href="/ruby/">Ruby</a></li>
+       
+               <li><input name="soa" value="true" checked="checked" id="community2" onclick="includeExcludeCommunity(this);" type="checkbox">
+ <a href="/soa/">SOA</a></li>
+       
+               <li><input name="agile" value="true" checked="checked" id="community3" onclick="includeExcludeCommunity(this);" type="checkbox">
+ <a href="/agile/">Agile</a></li>
+       
+               <li><input name="architecture" value="true" checked="checked" id="community1389" onclick="includeExcludeCommunity(this);" type="checkbox">
+ <a href="/architecture/">Architecture</a></li>
+       
+    </ul>
+</div>
+<div id="communitiesMessage"></div>
+    </div></div>
+    <div class="bottom-corners"><div></div></div>
+</div>
+
+
+
+               
+
+
+
+
+
+<script type="text/javascript">
+       function doSearch(){
+               var searchString = document.getElementById("searchId").value;
+               document.getElementById("searchTerm").value =  searchString + " site:www.infoq.com";            
+               document.getElementById("submitForm").submit();
+       }
+       
+       function clearSearchText(){     
+               var searchtext =  document.getElementById("searchId").value
+               if(searchtext==JSResource.search){
+                       document.getElementById("searchId").value="";
+               }
+       }
+</script>
+<form action="http://www.google.com/search" method="get" id="submitForm" target="_blank">
+       <input name="q" id="searchTerm" type="hidden">
+</form>
+
+       <div style="background: transparent url(/images/bg-search.gif) no-repeat scroll 0pt 4px; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">       
+                       <input name="search" id="searchId" value="Search" style="border: 0px none ; padding: 0pt 9px; width: 85%; background-color: transparent; height: 19px;" onclick="clearSearchText();" onkeypress="if ((event.which && event.which == 13)||(event.keyCode && event.keyCode == 13)){doSearch();}" onblur="if(this.value=='') this.value=JSResource.search" type="text">    
+                       <a href="#" onclick="doSearch();return false;"><img src="/images/btn-search.gif" alt="Search"></a> 
+       </div>
+
+               
+
+
+
+
+<div class="box-simple">
+<div class="box-simple-top"></div>
+<div id="featuredTopics" class="box-simple-content">
+       
+
+
+
+
+
+    <h2>Featured Topics</h2>
+    <div>
+               <ul>
+            <li><a href="/virtualization/">Virtualization</a></li>
+            <li><hr style="border: 0pt none ; width: 100%; height: 1px; color: rgb(200, 200, 200); background-color: rgb(200, 200, 200);"></li>
+            <li><a href="/performance-scalability/">Performance &amp; Scalability</a></li>
+            <li><hr style="border: 0pt none ; width: 100%; height: 1px; color: rgb(200, 200, 200); background-color: rgb(200, 200, 200);"></li>
+            <li><a href="/rest/">REST &amp; Web Architecture</a></li>
+            <li><hr style="border: 0pt none ; width: 100%; height: 1px; color: rgb(200, 200, 200); background-color: rgb(200, 200, 200);"></li>
+            <li><a href="/governance/">SOA Governance</a></li>
+               </ul>
+       </div>
+               
+       
+
+</div>
+<div class="box-simple-bottom"></div>
+</div>
+
+               
+
+
+
+
+
+
+       <div class="box-simple">
+               <div class="box-simple-top"></div>
+               <div class="box-simple-content adsTower2" id="leftbartextlinks">
+                       <div style="background: white none repeat scroll 0%; width: 120px; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
+                               
+
+
+
+
+
+<h3>Sponsored Links</h3>
+
+
+<p><a id="tl-53" onclick="Ads.clickTextLink(this, 53);" href="http://www.projectzero.org/" target="_blank">Create&nbsp;REST<br>-enabled&nbsp;Web&nbsp;Apps</a><br>with&nbsp;Project&nbsp;Zero<br>from&nbsp;IBM.</p>
+
+<p><a id="tl-76" onclick="Ads.clickTextLink(this, 76);" href="http://www-306.ibm.com/software/webservers/appserv/extend/virtualenterprise/" target="_blank">IBM WebSphere</a><br>Virtualize apps<br>to lower costs,<br>Increase agility<br><a id="tl-76" onclick="Ads.clickTextLink(this, 76);" href="http://www-306.ibm.com/software/webservers/appserv/extend/virtualenterprise/" target="_blank">Learn more!</a></p>
+
+<p>Terracotta:<br>Scale your<br>Apps w/ease<br>Offload the DB:<br><a id="tl-79" onclick="Ads.clickTextLink(this, 79);" href="http://www.terracotta.org/confluence/display/orgsite/Download" target="_blank">Learn More!</a></p>
+
+
+                       </div>
+               </div>
+               <div class="box-simple-bottom"></div>
+       </div>
+
+
+<div class="box-simple">
+       <div class="box-simple-top"></div>
+       <div class="box-simple-content">
+               <p class="banner" id="bannerparagraph">
+                       
+
+
+
+
+
+       <a class="towerAdLeft" id="sk-59" href="http://www.versionone.com/getfreeteam" onclick="Ads.clickSkyscraper(this, 59 );" target="_blank"><img style="display: none;" src="/ads/VersionOneBanner.gif"></a>
+
+
+
+               </p>
+       </div>
+       <div class="box-simple-bottom"></div>
+</div>
+
+<div class="box-simple">
+       <div class="box-simple-top"></div>
+       <div class="box-simple-content">
+               <p class="banner">
+                       <img style="display: none;" src="/styles/i/banners/books.gif" usemap="#booksmap" alt="">
+                       <map name="booksmap"><area href="http://www.infoq.com/minibooks/scrum-xp-from-the-trenches" alt="Scrum and XP from the Trenches" title="Scrum and XP from the Trenches" shape="rect" coords="0,75,120,100"><area href="http://www.infoq.com/minibooks/starting-struts2" alt="Starting Struts 2" title="Starting Struts 2" shape="rect" coords="0,110,120,125"><area href="http://www.infoq.com/minibooks/agile-patterns" alt="Agile Patterns: The Technical Cluster" title="Agile Patterns: The Technical Cluster" shape="rect" coords="0,130,120,160"><area href="http://www.infoq.com/minibooks/ruby" alt="Mr. Neighborly's Humble Little Ruby Book" title="Mr. Neighborly's Humble Little Ruby Book" shape="rect" coords="0,165,120,205"><area href="http://www.infoq.com/minibooks/grails" alt="Getting Started with Grails" title="Getting Started with Grails" shape="rect" coords="0,210,120,235"><area href="http://www.infoq.com/minibooks/domain-driven-design-quickly" alt="Domain Driven Design Quickly" title="Domain Driven Design Quickly" shape="rect" coords="0,245,120,270"><area href="http://www.infoq.com/minibooks/scrum-checklists" alt="Scrum Checklists" title="Scrum Checklists" shape="rect" coords="0,275,120,290"><area href="http://www.infoq.com/minibooks/enterprise-soa" alt="Enterprise SOA Adoption Strategies" title="Enterprise SOA Adoption Strategies" shape="rect" coords="0,300,120,323"><area href="http://www.infoq.com/minibooks/vsnettt" alt="Visual Studio .NET Tips and Tricks" title="Visual Studio .NET Tips and Tricks" shape="rect" coords="0,330,120,355"><area href="http://www.infoq.com/minibooks/JTDS" alt="Java Transaction Design Strategies" title="Java Transaction Design Strategies" shape="rect" coords="0,365,120,390">
+                               
+                                                       
+                               
+                               
+                               
+                               
+                               
+                               
+                               
+                               
+                       </map>
+               </p>
+       </div>
+    <div class="box-simple-bottom"></div>
+</div>
+
+                               
+               <div class="sidebar-bottom"></div>
+       </div>
+       </div>
+       
+
+       <div id="clearer"></div>
+
+       
+       <div id="content">
+       <div id="content-wrapper">
+               
+               <div class="box">
+                       
+                       
+
+    <h2>Interview</h2>
+    <div class="top-corners"><div></div></div> 
+    <div class="box-content">
+    <div class="box-content-2">
+    <div class="box-content-3">
+       
+    <div style="padding: 3px 0pt; clear: both; width: 100%; background-color: rgb(254, 255, 191); margin-bottom: 10px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; -moz-border-radius-bottomright: 5px; -moz-border-radius-bottomleft: 5px;">
+           &nbsp;&nbsp;&nbsp;<b>Good News:</b>&nbsp;We have re-worked our video infrastructure to provide more reliable service. Please email bugs at infoq.com with any problems.
+    </div>
+    
+    <h1>Jim Weirich Discusses Rake,  the Ruby Make Tool </h1>
+
+       <p class="info">
+               Interview with
+               <strong>Jim Weirich</strong>
+         
+            by
+            <strong>Werner Schuster</strong>
+        
+               on
+               Apr 17, 2008 03:12 AM
+       </p>
+       <dl class="tags2">
+               <dt class="community">Community</dt>
+                       
+                               <dd><a href="/ruby" name="ruby" id="5" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Ruby</a></dd>
+                       
+           <dt class="topics">Topics</dt>
+                       
+                               <dd><a href="/dsl" name="dsl" id="176" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Domain Specific Languages</a>,</dd>
+                       
+                               <dd><a href="/builds" name="builds" id="12" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Build systems</a></dd>
+                       
+                       
+                       <dt class="topics">Tags</dt>
+                       
+                               <dd><a href="/rake" name="rake" id="178" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Rake</a>,</dd>
+                       
+                               <dd><a href="/mocks" name="mocks" id="288" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Mocks</a></dd>
+                       
+               
+    </dl>
+
+       <script type="text/javascript">
+       var TIMES = new Array(0,94,214,220,250,309,328,365,484,630,761,838,852,859,919,981,1012,1177,1239,1378,1472,1483,1616,1640,1658,1720,1731,1771,1868,1897,1900,1915);
+               var ACTION_IMG_EXPAND = '/styles/i/icon-open.gif';
+               var ACTION_IMG_COLLAPSE = '/styles/i/icon-collapse.gif';
+           var jsclassref='aHR0cDovL2Zsdi50aHJ1aGVyZS5uZXQvaW50ZXJ2aWV3cy9KaW1XZWlyaWNoLmZsdg==';
+       </script>
+
+       
+       
+       <div id="interviewContent" style="width: 100%;">Please install <a target="_blank" href="http://www.adobe.com/go/getflashplayer">Flash player</a>.</div>
+
+       <script type="text/javascript">
+               FlashDetect.check(9, "interviewContent", "The interview player requires <a href='http://www.macromedia.com/go/getflashplayer' target='_blank'>Flash version 9</a>.", "Please install <a target='_blank' href='http://www.adobe.com/go/getflashplayer'>Flash player</a>.");
+       </script>  
+
+       <div style="display: block; margin-top: 15px;">
+        <div style="display: inline; margin-right: 0px;" align="right">
+            
+            
+
+
+
+
+<dl class="tags3">
+<dt>Bookmark</dt>
+<dd>
+<a target="_blank" href="" onclick="this.href='http://digg.com/submit?phase=2&url=' + escape(window.location)" rel="nofollow">digg+</a>,
+</dd>
+<dd>
+<a target="_blank" href="" onclick="this.href='http://reddit.com/submit?url=' + escape(window.location) + '&title=' + escape('Jim Weirich Discusses Rake,  the Ruby Make Tool ')" rel="nofollow">reddit+</a>,
+</dd>
+<dd>
+<a target="_blank" href="" onclick="this.href='http://del.icio.us/post?url=' + escape(window.location) + '&title=' + escape('Jim Weirich Discusses Rake,  the Ruby Make Tool ')" rel="nofollow">del.icio.us+</a>,
+</dd>
+<dd>
+<a target="_blank" href="" onclick="this.href='http://www.dzone.com/links/add.html?url=' + escape(window.location) + '&title=' + escape('Jim Weirich Discusses Rake,  the Ruby Make Tool ')" rel="nofollow">dzone+</a>,
+</dd>
+<dd>
+<a target="_blank" href="" onclick="this.href='http://www.facebook.com/share.php?u=' + escape(window.location)" rel="nofollow">facebook+</a>
+</dd>
+</dl>
+
+        </div>
+               
+       </div>
+                       
+       
+
+
+
+
+
+
+<div class="vendor-content-box">
+       
+       <h3>Related<span class="vendor">Vendor</span>Content</h3>
+       
+       
+               
+                       
+               
+               <p class="entrypdf">
+                       <a href="/vendorcontent/show.action?vcr=213" target="_blank">
+                               Introducing Project Zero: Building RESTful services for your Web application 
+                       </a>
+               </p>
+       
+               
+                       
+               
+               <p class="entrypdf">
+                       <a href="/vendorcontent/show.action?vcr=294">
+                               Agile Tool Evaluation Guide
+                       </a>
+               </p>
+       
+               
+                       
+               
+               <p class="entrypdf">
+                       <a href="/vendorcontent/show.action?vcr=293">
+                               Evaluation Guide: Is Your SCM Tool Ready for Agile?
+                       </a>
+               </p>
+       
+               
+                       
+               
+               <p class="entrypdf">
+                       <a href="/vendorcontent/show.action?vcr=312" target="_blank">
+                               IBM software architect eKit:  Grady Booch podcast, whitepapers, articles
+                       </a>
+               </p>
+       
+               
+                       
+               
+               <p class="entrypdf">
+                       <a href="/vendorcontent/show.action?vcr=313" target="_blank">
+                               IBM Agile Development eKit: Free Articles, Expert Q&amp;A, Educational Resources
+                       </a>
+               </p>
+       
+       
+       
+       
+       
+       
+       
+</div>
+
+
+       
+       
+               
+       
+
+
+
+
+<script type="text/javascript">
+var replyEnabled=true;
+var forumID=1;
+var threadID=5920;
+var previewText='Preview';
+var pleaseWait='Please Wait ...';      
+var reply='Reply';
+var postMessage='Post Message';        
+var errorSubject='Please enter a subject.';    
+var errorBody='You can not post a blank message. Please type your message and try again.';
+var cancel='Cancel';
+var goBackOrEdit='Go Back/Edit';
+var re='Re:';
+var lastMessage=0;
+var stopWatchText='Stop Watching Thread';
+var startWatchText='Watch Thread';
+var descending='false';
+var ctxPath= '';
+var postAddress= ctxPath + '/forum/post!post.action?language=' + 'en';
+var postAddWatches= ctxPath + '/forum/watches!add.action';
+var postRemoveWatches= ctxPath + '/forum/watches!remove.action';
+var loggedIn=false;    
+</script>
+
+<script src="/scripts/forum.js?rev=new" type="text/javascript"></script>
+
+       <div class="comments-header">
+           <h3>No comments</h3>
+           <p>
+                               
+                       <a href="javascript:void(0)" class="comment-reply" onclick="javascript:loggedIn?replyFromTooltip(21380,true):showLoginWindow(this,ALIGN_RIGHT,new Function('replyFromTooltip(21380,true)'));">Reply</a>
+               </p>
+       </div>
+       
+       <span id="newMessage" style="display: none;"></span>
+       
+       <span id="replyTree_21380"></span>              
+       <span id="replyMessage_21380"></span>
+       
+       
+       <div class="comments-sort">
+               <span id="comments-sort" style="display: none;">
+                       
+                       
+                               <a class="comment-sort-desc" href="javascript:changeOrder(2);">Sort by date descending</a>
+                       
+               </span>
+       </div>
+       
+       <ol class="comments">
+       
+       
+       
+       
+       <span id="lastMessages"></span>
+       <span id="replyFlatMessage_21380"></span>
+       
+       </ol>
+
+
+       
+    <div class="box-bottom"></div>
+    </div>
+    </div> 
+    <div class="bottom-corners"><div></div></div>
+    </div> 
+  
+
+                       
+               </div>
+               
+       </div></div>
+       
+               
+       
+
+
+
+
+
+<!-- right side start -->
+
+       <div id="rightbar">
+       <div id="right-wrapper">
+           <!-- box start -->
+           <div class="box">
+               <h2>Exclusive Content</h2>
+               <ul class="menu" id="tabsmenu">
+                               <li id="tab_ALL_EXCEPT_NEWS" class="m-ALL_EXCEPT_NEWS-on"><a href="#" onclick="ContentSummary.switchTab('ALL_EXCEPT_NEWS');return false;">All</a></li>
+                   <li id="tab_ARTICLE" class="m-ARTICLE-off"><a href="#" onclick="ContentSummary.switchTab('ARTICLE');return false;">Articles</a></li>
+                   <li id="tab_PRESENTATION" class="m-PRESENTATION-off"><a href="#" onclick="JSResource.presentationsTab();return false;">Presentations</a></li>
+                   <li id="tab_INTERVIEW" class="m-INTERVIEW-off"><a href="#" onclick="JSResource.interviewsTab();return false;">Interviews</a></li>
+                   <li id="tab_MINIBOOK" class="m-MINIBOOK-off"><a href="#" onclick="JSResource.minibooksTab();return false;">Minibooks</a></li>
+               </ul>
+                   <div class="top-corners"><div></div></div>
+                   
+                   <div class="box-content">
+                           <div class="box-content-2">
+                           <div id="rightbarcontentbox" class="box-content-3">
+                                       
+                                               
+                                       
+
+
+
+
+
+<form id="tabstateform" action="">
+       <input id="startIndex" name="startIndex" value="0" type="hidden">
+       <input id="selectedTab" name="selectedTab" value="ALL_EXCEPT_NEWS" type="hidden">
+       <input id="rightBarLanguage" name="language" value="en" type="hidden">
+</form>
+
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-interviews"><a href="/interviews/bryant-ruby-maglev-gemstone">Avi Bryant on MagLev and GemStone </a></h1>
+       
+               <p class="image"><a href="/interviews/bryant-ruby-maglev-gemstone"><img src="/resource/interviews/bryant-ruby-maglev-gemstone/en/smallimage/AviBryant.jpg" alt=""></a></p>
+        
+        <p>Avi Bryant talks about working on MagLev, a Ruby implementation built by GemStone. Avi explains the reasons for MagLev, the merits of GemStone's distributed OODB features, and more.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/architecture" name="architecture" id="1,389" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Architecture</a>,
+                       
+                               <a href="/ruby" name="ruby" id="5" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Ruby</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 13, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/interviews/bryant-ruby-maglev-gemstone"><span>&nbsp;</span>
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-articles"><a href="/articles/rising-agile-spirit-numbers">Using Numbers to Communicate - in the Spirit of Agile</a></h1>
+       
+               <p class="image"><a href="/articles/rising-agile-spirit-numbers"><img src="/resource/articles/rising-agile-spirit-numbers/en/smallimage/Spirit_of_Agile_small.jpg" alt=""></a></p>
+        
+        <p>Developers and the business use numbers differently, leading to poor communication. Here the "Spirit of Agile" tells a developer the trick: translate non-computational issues into number language.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/agile" name="agile" id="3" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Agile</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 13, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/articles/rising-agile-spirit-numbers"><span>&nbsp;</span>
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-presentations"><a href="/presentations/Agile-Adoption-Joseph-Pelrine">Dealing With the Organizational Challenges of Agile Adoption</a></h1>
+       
+               <p class="image"><a href="/presentations/Agile-Adoption-Joseph-Pelrine"><img src="/resource/presentations/Agile-Adoption-Joseph-Pelrine/en/smallimage/JPelrine.jpg" alt=""></a></p>
+        
+        <p>In this presentation filmed during QCon London 2007, Joseph Pelrine talks about the challenges faced by organizations trying to adopt Agile methods.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/agile" name="agile" id="3" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Agile</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 12, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/presentations/Agile-Adoption-Joseph-Pelrine"><span>&nbsp;</span>
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-articles"><a href="/articles/ddd-in-practice">Domain Driven Design and Development In Practice</a></h1>
+       
+               <p class="image"><a href="/articles/ddd-in-practice"><img src="/resource/articles/ddd-in-practice/en/smallimage/imagesmall.gif" alt=""></a></p>
+        
+        <p>In this article, Srini Penchikala discusses Domain Driven Design from a practical stand-point. The article looks at architectural guidelines and best practices that can be used in a DDD project.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/architecture" name="architecture" id="1,389" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Architecture</a>,
+                       
+                               <a href="/java" name="java" id="1" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Java</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 12, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/articles/ddd-in-practice"><span>&nbsp;</span>
+                               
+                                       6
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-presentations"><a href="/presentations/colyer-server-side-osgi">Server Side OSGi</a></h1>
+       
+               <p class="image"><a href="/presentations/colyer-server-side-osgi"><img src="/resource/presentations/colyer-server-side-osgi/en/smallimage/AdrianColyer.jpg" alt=""></a></p>
+        
+        <p>Adrian Colyer describes OSGi, OSGi implementations, modularity, versioning, operational control, server-side OSGi, design considerations, using existing libraries, and Spring Dynamic Modules.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/java" name="java" id="1" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Java</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 11, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/presentations/colyer-server-side-osgi"><span>&nbsp;</span>
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-presentations"><a href="/presentations/Agile-Architecture-Is-Not-Fragile-Architecture-James-Coplien-Kevlin-Henney">Agile Architecture Is Not Fragile Architecture</a></h1>
+       
+               <p class="image"><a href="/presentations/Agile-Architecture-Is-Not-Fragile-Architecture-James-Coplien-Kevlin-Henney"><img src="/resource/presentations/Agile-Architecture-Is-Not-Fragile-Architecture-James-Coplien-Kevlin-Henney/en/smallimage/coplienhenney.jpg" alt=""></a></p>
+        
+        <p>In this presentation filmed during QCon 2007, Coplien and Henney describe how to start with enough architecture to ensure long term success of an Agile developed project.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/architecture" name="architecture" id="1,389" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Architecture</a>,
+                       
+                               <a href="/agile" name="agile" id="3" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Agile</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 10, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/presentations/Agile-Architecture-Is-Not-Fragile-Architecture-James-Coplien-Kevlin-Henney"><span>&nbsp;</span>
+                               
+                                       3
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-articles"><a href="/articles/nuescheler-jcr-rest">David Nuescheler on JCR and REST</a></h1>
+       
+               <p class="image"><a href="/articles/nuescheler-jcr-rest"><img src="/resource/articles/nuescheler-jcr-rest/en/smallimage/files.jpg" alt=""></a></p>
+        
+        <p>In this interview, Day CTO and JCR Spec Lead David Nuescheler discusses JCR, the Java Content Repository standard, its connection to REST, and the Sling web framework.</p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/java" name="java" id="1" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Java</a>,
+                       
+                               <a href="/soa" name="soa" id="2" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">SOA</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 10, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/articles/nuescheler-jcr-rest"><span>&nbsp;</span>
+                               
+                                       1
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+       
+               
+       
+       <div class="entry">
+       <h1 class="ex-articles"><a href="/articles/nasdaq-case-study-air-and-s3">InfoQ Case Study: NASDAQ Market Replay</a></h1>
+       
+               <p class="image"><a href="/articles/nasdaq-case-study-air-and-s3"><img src="/resource/articles/nasdaq-case-study-air-and-s3/en/smallimage/image_amazon_air.jpg" alt=""></a></p>
+        
+        <p>In this case study InfoQ reviews the usage of Adobe AIR and Amazon Simple Storage Service (S3) in the NASDAQ Market Replay application.  </p>
+        <ul class="info link-col">
+            <li>
+                       
+                               <a href="/architecture" name="architecture" id="1,389" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Architecture</a>,
+                       
+                               <a href="/java" name="java" id="1" onclick="try {CategoryPopup.showPopup(this);} catch(e) {}; return false;">Java</a>,
+                       
+                       </li>
+               <li class="author"><span>&nbsp;</span>Jun 09, 2008,</li>
+           
+               <li class="comments">
+                       <a href="/articles/nasdaq-case-study-air-and-s3"><span>&nbsp;</span>
+                               
+                                       1
+                                                               
+                       </a>
+                   </li>
+                
+        </ul>
+    </div>
+        
+    <div class="clearer"></div>
+
+
+
+<ul class="newsnav link-col">
+
+
+
+
+    <li><a href="#" onclick="ContentSummary.setStartIndex('8');return false;">Older &gt;</a></li>
+
+
+
+</ul>
+
+       
+                                   <div class="box-bottom"></div>
+                               </div>
+                               </div>
+                               <div class="bottom-corners"><div></div></div>
+                       </div>
+               </div>
+               <!-- box end -->
+               <script type="text/javascript">
+                       ContentSummary.setSelectedTab('en');
+               </script>
+       </div>
+       </div>
+
+<!-- right side end -->
+
+
+       <div class="clearer"></div>
+
+       
+
+
+
+
+
+
+       <div id="footer">
+               <p>
+                       InfoQ.com and all content copyright © 2006-2007 C4Media Inc.
+                       InfoQ.com hosted at <a href="http://www.contegix.com/">Contegix</a>, the best ISP we've ever worked with.
+                       <a href="/PrivacyPolicy.jsp">Privacy policy</a>
+               </p>
+       </div>
+
+
+</div>
+
+
+
+
+
+
+<script type="text/javascript">
+       var includeName = 'Include';
+       var excludeName = 'Exclude';
+       var includeHint = 'You can include this category.';
+       var excludeHint = 'You can exclude this category.';
+       var excludeCategoryMessage = 'You can re-include from your profile personalization, or right now.<BR />';
+       var viewallCategoryMessage = 'You can view all items that belong to this category.';
+       var busyMessage = 'Please wait...';
+       var contextPath = '' + '/';
+       var viewallCategoryPath= 'en';
+       var includeExcludeLink= true;
+</script>
+
+</body>​​​​​</html>
\ No newline at end of file
diff --git a/test/infoq_remote_test.rb b/test/infoq_remote_test.rb
new file mode 100644 (file)
index 0000000..7700d6b
--- /dev/null
@@ -0,0 +1,21 @@
+# Remote Infoq tests. Actually hit their website
+# and attempt to parse the data returned.
+
+require 'test/unit'
+require 'src/websites/infoq'
+
+class InfoqRemoteTest < Test::Unit::TestCase
+  
+  def test_get_page_data
+    iq = Infoq.new()
+
+    # We can't rely on the fixture here, because Infoq might
+    # change their page layout. Instead, check that we can actually
+    # find the base64 regex (containing the FLV URL).
+    page_data = iq.send('get_page_data', 'http://www.infoq.com/interviews/jim-weirich-discusses-rake')
+    
+    test_result = iq.get_video_url(page_data)
+    assert_equal('http://flv.thruhere.net/interviews/JimWeirich.flv', test_result)
+  end
+    
+end
diff --git a/test/infoq_test.rb b/test/infoq_test.rb
new file mode 100644 (file)
index 0000000..51d1a3f
--- /dev/null
@@ -0,0 +1,27 @@
+# Unit tests for the Infoq class. Basically just checking
+# the results of parse_video_url for now.
+
+require 'test/unit'
+require 'src/websites/infoq'
+
+class InfoqTest < Test::Unit::TestCase
+
+  def test_owns_infoq_urls
+    assert(Infoq.owns_url?('http://www.infoq.com/interviews/jim-weirich-discusses-rake'))
+  end
+
+  
+  def test_parse_video_url
+    iq = Infoq.new()
+    
+    page_data = nil
+    
+    File.open('test/fixtures/infoq/jim-weirich-discusses-rake.html') do |f|
+      page_data = f.read
+    end
+    
+    test_result = iq.send('parse_video_url', page_data)
+    assert_equal('http://flv.thruhere.net/interviews/JimWeirich.flv', test_result)
+  end
+
+end
index 200e795562ec87e7e9ab6a185699093ab04b0a47..d4085d9fb4697f7030717f4b84d34844b54e7f66 100644 (file)
@@ -1 +1,2 @@
+require 'test/infoq_remote_test'
 require 'test/youporn_remote_test'
index 5b01b0e8a152f220b77d0dd8666816ad34e9fa0a..ddc078ebc6ba19c4477e61f841c9dd5dda2e6e11 100644 (file)
@@ -1,4 +1,5 @@
 require 'test/howcast_test'
+require 'test/infoq_test'
 require 'test/redtube_test'
 require 'test/website_test'
 require 'test/youporn_test'