woot 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ Scrapes woot.com sites
9
9
  == Usage
10
10
 
11
11
  Simply call <tt>Woot.scrape</tt> and optionally specify the woot subdomain (e.g. www, shirt, kids, wine, etc).
12
- Defaults to www.
12
+ Defaults to www. Returns a Struct object.
13
13
 
14
14
  woot = Woot.scrape
15
15
  puts woot.title
@@ -38,10 +38,6 @@ Call <tt>Woot.stop</tt> to stop streaming.
38
38
  bump version in a commit by itself I can ignore when I pull)
39
39
  * Send me a pull request. Bonus points for topic branches.
40
40
 
41
- == Todo
42
-
43
- * parsing and streaming tests
44
-
45
41
  == Copyright
46
42
 
47
43
  Copyright (c) 2009 Sean Huber. See MIT-LICENSE for details.
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ begin
12
12
  gem.authors = ['Sean Huber']
13
13
  gem.add_dependency 'scrapi'
14
14
  gem.add_dependency 'tweetstream'
15
+ gem.add_development_dependency 'fakeweb'
15
16
  gem.add_development_dependency 'shoulda'
16
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
18
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.7
@@ -41,13 +41,14 @@ class Woot
41
41
  '*' => { :subdomain => proc { |element| subdomain.to_s } },
42
42
  'h2.fn' => { :title => :text },
43
43
  'span.amount' => { :price => :text },
44
+ 'abbr.currency' => { :currency => '@title', :currency_symbol => :text },
44
45
  'ul#shippingOptions' => { :shipping => :text },
45
46
  'img.photo' => { :image => '@src' },
46
47
  'div.hproduct>a' => { :alternate_image => proc { |element| $1 if element.attributes['href'] =~ /\('([^']+)'\);/ } },
47
48
  'a.url' => { :url => '@href' },
48
49
  'li.comments>a' => { :comments_url => '@href', :comments_count => proc { |element| element.children[0].content.gsub(/\D/, '') } },
49
50
  'div.story>h2' => { :header => :text },
50
- 'div.story>h3' => { :sub_header => :text },
51
+ 'div.story>h3' => { :subheader => :text },
51
52
  'div.writeUp' => { :writeup => :text },
52
53
  'div.specs' => { :specs => :text },
53
54
  'div.productDescription>dl' => { :details => :text },
@@ -59,8 +60,7 @@ class Woot
59
60
 
60
61
  def self.stream(twitter_username, twitter_password)
61
62
  TweetStream::Client.new(twitter_username, twitter_password).follow(*TWITTER_IDS.values) do |status|
62
- subdomain = TWITTER_IDS.index(status.user.id)
63
- subdomain = $1 if subdomain == WOOT_OFF && subdomain =~ /https?:\/\/([^\.]+)\.#{DOMAIN}/
63
+ subdomain = subdomain_from_twitter_status(status)
64
64
  yield scrape(subdomain) unless subdomain.nil?
65
65
  end
66
66
  end
@@ -68,4 +68,12 @@ class Woot
68
68
  def self.stop
69
69
  TweetStream::Client.stop
70
70
  end
71
+
72
+ protected
73
+
74
+ def self.subdomain_from_twitter_status(status)
75
+ subdomain = TWITTER_IDS.index(status.user.id)
76
+ subdomain = (status.text =~ /(\w+)\.#{DOMAIN}/ ? $1 : nil) if subdomain == WOOT_OFF
77
+ subdomain
78
+ end
71
79
  end
@@ -0,0 +1,603 @@
1
+
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml">
4
+ <head id="ctl00_ctl00_Head"><title>
5
+ Woot : One Day, One Deal (SM)
6
+ </title>
7
+ <script type="text/javascript">document.write(unescape("%3Cscript src='" + document.location.protocol + "//ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js' type='text/javascript'%3E%3C/script%3E"));</script>
8
+
9
+
10
+ <link rel="icon" href="http://gzip.static.woot.com/App_Themes/Woot/favicon.5.ico" type="image/x-icon" /><link rel="shortcut icon" href="http://gzip.static.woot.com/App_Themes/Woot/favicon.5.ico" type="image/x-icon" /><link rel="apple-touch-icon" href="http://gzip.static.woot.com/App_Themes/Woot/Images/apple-touch-icon.5.png" /><link rel='search' type='application/opensearchdescription+xml' title='Woot' href='/Search/OpenSearch.ashx' /><link href='http://gzip.static.woot.com/Styles/MasterPage.min.5034.css' rel='stylesheet' type='text/css' /><link href='Blog/Feed.ashx' rel='alternate' title='RSS' type='application/rss+xml' /><link rel="microsummary" type="application/x.microsummary+xml" href="DefaultMicrosummary.ashx" /><link rel="microsummary" type="application/x.microsummary+xml" href="DefaultReversedMicrosummary.ashx" /><link href='http://gzip.static.woot.com/Styles/HomePage.min.5034.css' rel='stylesheet' type='text/css' /><link href='http://gzip.static.woot.com/App_Themes/Woot/Styles/Theme.min.5034.css' rel='stylesheet' type='text/css' /></head>
11
+ <body id="ctl00_ctl00_Body" class="todaysWoot">
12
+ <div class="clearfix" id="header">
13
+ <h1>
14
+ <a href="./" class="logo">Woot : One Day, One Deal (SM)</a>
15
+
16
+ </h1>
17
+ <script type="text/javascript">
18
+ function showLoginForm() {
19
+ $('#loginLink').hide();
20
+ $('#loginForm').show();
21
+ $('#username').focus();
22
+ }
23
+ </script>
24
+ <div id="login">
25
+ <noscript>
26
+
27
+
28
+ <h4>Welcome back!</h4>
29
+ <p><a href='https://sslwww.woot.com/Member/YourAccount.aspx'>My account</a> | <a href='https://account.woot.com/logout?returnurl=http%3a%2f%2fwww.woot.com%2fdefault.aspx'>Log out</a></p>
30
+
31
+ </noscript>
32
+ <div id="loggedIn" style="display:none;">
33
+ <h4>Welcome <span class="username"></span><span class="qube"></span></h4>
34
+ <p><a href='https://sslwww.woot.com/Member/YourAccount.aspx'>My account</a> | <a href='https://account.woot.com/logout?returnurl=http%3a%2f%2fwww.woot.com%2fdefault.aspx'>Log out</a></p>
35
+ </div>
36
+ <div id="loggedOut" style="display:none;">
37
+ <div id="loginLink">
38
+ <h4><a href="https://account.woot.com/login?returnurl=http%3a%2f%2fwww.woot.com%2fdefault.aspx" onclick="showLoginForm(); return false;">Log in</a></h4>
39
+ </div>
40
+ <div id="loginForm" style="display:none;">
41
+ <form action='https://account.woot.com/login?returnurl=http%3a%2f%2fwww.woot.com%2fdefault.aspx' method="post">
42
+ <ul class="clearfix">
43
+ <li>
44
+ <input id="username" name="username" tabindex="1" type="text" />
45
+ <span>username</span>
46
+ </li>
47
+ <li>
48
+ <input name="password" tabindex="2" type="password" />
49
+ <span>password <a href='https://sslwww.woot.com/User/ForgotPassword.aspx'>(forget?)</a></span>
50
+ </li>
51
+ <li id="loginSubmit">
52
+ <input tabindex="3" type="submit" value="Go" />
53
+ </li>
54
+ </ul>
55
+ </form>
56
+ </div>
57
+ <p>Hi, are you new? <a href='https://sslwww.woot.com/User/Register.aspx'>Start here</a>.</p>
58
+ </div>
59
+ </div>
60
+
61
+ <ul class="nav">
62
+ <li id="navTodaysWoot"><a href="/"><span>Today's Woot</span></a></li>
63
+ <li id="navBlog"><a href="/Blog/"><span>Blog</span></a></li>
64
+ <li id="navCommunity"><a href="/Forums/"><span>Community</span></a></li>
65
+ <li id="navWriteUs"><a href="/WriteUs.aspx"><span>Write Us</span></a></li>
66
+ <li id="navWhatIsWoot"><a href="/WhatIsWoot.aspx"><span>What Is Woot?</span></a></li>
67
+ </ul>
68
+ </div>
69
+ <form name="aspnetForm" method="post" action="default.aspx" id="aspnetForm">
70
+ <div>
71
+ <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNDMwNzE3MDMwZGTHscstbp0E2jJMrd8uGXSlJpAbZw==" />
72
+ </div>
73
+
74
+
75
+ <script src="http://gzip.static.woot.com/Scripts/jquery.corner.min.5034.js" type="text/javascript"></script>
76
+ <script src="http://gzip.static.woot.com/Scripts/jquery.simplemodal.min.5034.js" type="text/javascript"></script>
77
+ <script src="http://gzip.static.woot.com/Scripts/MasterPage.min.5034.js" type="text/javascript"></script>
78
+ <script src="http://gzip.static.woot.com/Scripts/jquery.qtip.min.5034.js" type="text/javascript"></script>
79
+ <script type="text/javascript">
80
+ //<![CDATA[
81
+ $(function() { $('.otherWootSite img').qtip(thumbnailQtipSettings); });//]]>
82
+ </script>
83
+
84
+ <script src="http://gzip.static.woot.com/Scripts/jquery.jscrollpane.min.5034.js" type="text/javascript"></script>
85
+ <script src="http://gzip.static.woot.com/Scripts/jquery.mousewheel.min.5034.js" type="text/javascript"></script>
86
+ <script src="http://partner.googleadservices.com/gampad/google_service.js" type="text/javascript"></script><script type="text/javascript">GS_googleAddAdSenseService('ca-pub-2332856072838068'); GS_googleEnableAllServices();</script><script type="text/javascript">GA_googleAddSlot('ca-pub-2332856072838068', 'woot-homeside1-300x250');</script><script type="text/javascript">GA_googleFetchAds();</script><script type="text/javascript">GA_googleAddSlot('ca-pub-2332856072838068', 'woot-homeside2-300x250');</script><script type="text/javascript">GA_googleAddSlot('ca-pub-2332856072838068', 'woot-homeside3-300x250');</script>
87
+
88
+ <p class="accessibility">Woot is the originator of One Day, One Deal. Every midnight (central) we launch an
89
+ event: one sale that lives until it sells out, or the next midnight.</p>
90
+ <div class="leadIn">
91
+
92
+
93
+
94
+ <div class="hproduct clearfix">
95
+ <a href="javascript:lightboxImage('http://sale.images.woot.com/Blockade_Noise_Isolating_Earbudsqx4Detail.jpg');"><img alt="Blockade Noise Isolating Earbuds - 2 Pack" class="photo" src="http://sale.images.woot.com/Blockade_Noise_Isolating_EarbudsmqlStandard.jpg" /></a>
96
+ <div class="productDescription">
97
+
98
+ <h2 class="fn">Blockade Noise Isolating Earbuds - 2 Pack</h2>
99
+ <h3 class="price"><span class="money"><abbr class="currency" title="USD" lang="en">$</abbr><span class="amount">14.99</span></span></h3>
100
+
101
+ <ul id="shippingOptions">
102
+
103
+ <li>+ $5 shipping</li>
104
+
105
+ </ul>
106
+
107
+
108
+ <a href='http://www.woot.com/sale/10457' class="url" style="display:none;"></a>
109
+ <dl>
110
+
111
+ <dt>Condition:</dt>
112
+ <dd>New</dd>
113
+ <dt>Product:</dt>
114
+
115
+ <dd>
116
+ 2 AO Safety 99014 Blockade Noise Isolating Earbuds
117
+
118
+ </dd>
119
+
120
+
121
+ </dl>
122
+ <h5><a id="ctl00_ctl00_ContentPlaceHolderLeadIn_ContentPlaceHolderLeadIn_SaleControl_HyperLinkWantOne" href="/WantOne.aspx?id=983db0c6-5c69-4737-926b-3697d4af542e">I Want One!</a></h5>
123
+ </div>
124
+ <!-- Event Codes -->
125
+
126
+ <div id="ctl00_ctl00_ContentPlaceHolderLeadIn_ContentPlaceHolderLeadIn_SaleControl_TwoForTuesdayPanel" class="eventCodeBottomLeft">
127
+
128
+ <img alt="Two for Tuesday" src="http://gzip.static.woot.com/App_Themes/Woot/Images/EventCodes/2 For Tuesday.gif" />
129
+
130
+ </div>
131
+
132
+ </div>
133
+
134
+ <div id="ctl00_ctl00_ContentPlaceHolderLeadIn_ContentPlaceHolderLeadIn_PanelSalebar" class="salebar">
135
+
136
+ <div class="module qualityPosts">
137
+ <div class="header">
138
+ <h3><a id="ctl00_ctl00_ContentPlaceHolderLeadIn_ContentPlaceHolderLeadIn_ctl00_ctl00_HyperLinkDiscussion" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554500">Discussion on Today's Woot</a></h3>
139
+ </div>
140
+ <div class="content">
141
+
142
+
143
+ <p>Kingmiwok wants to know if <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554729#3554729" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554729#3554729">the volume control is a powered circuit requiring a battery.</a></p>
144
+
145
+ <p>dlcarrier links to an <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554727#3554727" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554727#3554727">in-depth review.</a></p>
146
+
147
+ <p>twr8801 spotted a <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554713#3554713" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554713#3554713">collection of reviews.</a></p>
148
+
149
+ <p>step12 wonders about the <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554701#3554701" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554701#3554701">material</a>.</p>
150
+
151
+ <p>ImaginePeace24 inquires about <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554695#3554695" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554695#3554695">cord length</a>.</p>
152
+
153
+ <p>TMHF says, <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554642#3554642" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554642#3554642">"In all honesty though, the sound quality is pretty reasonable. Better, but not by much, than what you'd expect from two pairs that you get for 14.99."</a></p>
154
+
155
+ <p>smtatertot13 has <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554638#3554638" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554638#3554638">big ears</a>.</p>
156
+
157
+ <p>waacodemon demands answers, <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554633#3554633" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554633#3554633">"Why are there replacement tips? How cheap are these? "</a></p>
158
+
159
+ <p>wholloway6 wonders, <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554592#3554592" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554592#3554592">" Does anyone know if you can get different color foam pieces for these?"</a></p>
160
+
161
+ <p>theturtleguy worries about <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554589#3554589" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554589#3554589">power drain</a>.</p>
162
+
163
+ <p>duckcake asks, <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554553#3554553" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554553#3554553">" whats the yellow and black oval thingy in the middle?"</a></p>
164
+
165
+ <p>lafiremedic says, <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554546#3554546" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554546#3554546">"These are a great pair of earbuds. Good sound quality and easy fit."</a></p>
166
+
167
+ <p>DCno10 spots a <a href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554508#3554508" rel="nofollow" title="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554508#3554508">review</a>.</p>
168
+
169
+ </div>
170
+ <div class="footer">
171
+ <ul class="clearfix">
172
+ <li class="discuss"><a id="ctl00_ctl00_ContentPlaceHolderLeadIn_ContentPlaceHolderLeadIn_ctl00_ctl00_HyperLinkAllDiscussion" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554500">Join This Discussion</a></li>
173
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderLeadIn_ContentPlaceHolderLeadIn_ctl00_ctl00_HyperLinkCommentCount" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554500">71 comments</a></li>
174
+ </ul>
175
+ </div>
176
+ </div>
177
+
178
+ </div>
179
+
180
+
181
+ </div>
182
+ <div class="contentWrapper">
183
+ <div class="contentContainer clearfix">
184
+ <div class="arrow"></div>
185
+ <div class="mainContent clearfix">
186
+
187
+
188
+ <div class="story">
189
+ <h2>I think the little hairy guy with the claws is popping my bike tires on purpose</h2>
190
+ <h3>Head down, earbuds in, try not to get hit by a laser</h3>
191
+ <div class="writeUp"><p>My mother-in-law thought we were crazy. “You two are going to end up pulverized by a giant world-eating alien just like your Aunt Regina!” We’ve always wanted to live in Metro City, though, and when Jessica got that job offer at the Major Daily Newspaper, we were excited to move to where all the costumed action is.</p>
192
+ <p>For about the first three weeks, anyway.</p>
193
+ <p>When the errant meteorite hit the Volvo, we shrugged it off and started using public transportation. Then, our dog Scamp was eaten by the Crimson Cowl’s cyborg velociraptors. And around the fourth time some villain’s robot henchman gets plowed through your wall and into your living room without so much as a “Sorry, Citizens” from whatever hero happens to be on duty that day, you start to get a little annoyed.</p>
194
+ <p>I’m not complaining, really. That’s what cape insurance is for, after all. That’s the price you pay for living in the superhero capital of the world, I guess. You either pack your things and move to Wyoming, or you learn to adapt. It just takes a little adjusting.</p>
195
+ <p>So on the nights when the sky burns red with crisis or some silver-plated intergalactic herald is preaching doom and gloom all over the city, my wife and I plug the Blockade Noise Isolating Earbuds into our <span class="caps">MP3</span> players. The triple flange design provides optimal noise protection from all the laser blasts and explosions that flood the city soundscape, allowing us to concentrate on the music or audiobook we’re listening to. When I need to take a trip down to the corner market and have to jump out of the way of an automobile being thrown by some hulking gamma-irradiated scientist, the comfortable fit of these earbuds means the music stays in my ears. The integrated volume control in the cord is great for when I want to drown out any superhero bellowing witty banter, too.</p>
196
+ <p>If anyone knows a good way of keeping some of these heroes from perching on the gargoyle outside our bedroom window at night, though, I’d love to hear it. I know they’re just doing their inner-monologue thing, but it gets kinda creepy.</p></div>
197
+ <div class="specs">
198
+ <div style="float:right; margin:0 10px 10px 10px;">
199
+
200
+ <img src="Images/Icons/64x64/SmartPost.png" alt="SmartPost" />
201
+
202
+ </div>
203
+ <p><strong>Warranty:</strong> <a href="http://www.woot.com/user/warrantyinfo.htm" target="_blank">90 Day Woot Limited Warranty </a></p>
204
+ <p><strong>Features:</strong></p>
205
+ <ul>
206
+ <li>Patented triple-flange ear bud design provides optimal noise protection for an excellent fit that radically reduces noise</li>
207
+ <li>Integrated volume control places fingertip adjustment of any iPod or <span class="caps">MP3</span> player easily within reach</li>
208
+ <li>24 decibel Noise Reduction Rating brings an end to dangerously over-cranked tunes struggling to compete with loud external sounds</li>
209
+ <li>Use in the yard while mowing and gardening, in the workshop, on the job, in the gym or traveling on a plane to safely isolate background noise</li>
210
+ <li>Ultra comfortable design from the same company who brought you the industry leading WorkTunes</li>
211
+ <li>iPod and <span class="caps">MP3</span> compatible (any device with a 3.5mm plug)</li>
212
+ <li>Meets ANSI/OSHA Standards</li>
213
+ </ul>
214
+ <p><strong>Additional Photos:</strong></p>
215
+ <ul>
216
+ <li><a href="javascript:lightboxImage('http://sale.images.woot.com/AC10831A_specs1.jpg');">Blockade Noise Isolating Earbuds</a></li>
217
+ <li><a href="javascript:lightboxImage('http://sale.images.woot.com/AC10831A_specs2.jpg');">Volume Control</a></li>
218
+ <li><a href="javascript:lightboxImage('http://sale.images.woot.com/AC10831A_specs3.jpg');">Triple-flange ear bud design</a></li>
219
+ </ul>
220
+ <p><strong>In the box:</strong></p>
221
+ <ul>
222
+ <li><span class="caps">2 AO </span>Safety <span class="caps">99014 </span>Blockade Noise Isolating Earbuds</li>
223
+ <li>6 Extra Pairs of Ear Tips</li>
224
+ <li>2 Carrying Bags</li>
225
+ </ul>
226
+ </div>
227
+ <div class="rider"></div>
228
+ </div>
229
+ <div id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_PanelInnerbar" class="innerbar">
230
+ <div id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl00_PanelAdvertisement" class="module advertisement">
231
+
232
+ <div class="content">
233
+ <script type="text/javascript">GA_googleFillSlot('woot-homeside1-300x250');</script>
234
+ </div>
235
+ <div class="footer">
236
+ <p><a href="SponsorUs.aspx">Advertisement</a></p>
237
+ </div>
238
+
239
+ </div>
240
+ <div id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl01_PanelWootcast" class="module wootcast haudio hmedia">
241
+
242
+ <div class="header">
243
+ <h3><a id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl01_HyperLinkYourDailyWootcast" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554503">Today's Wootcast</a></h3>
244
+ <h4><a href="Blog/Feed.ashx?cat=Woot">RSS Feed</a></h4>
245
+ </div>
246
+ <div class="content">
247
+ <ul class="clearfix">
248
+ <li class="playButton">
249
+
250
+ <!-- object, two implementations nested + IE conditional comments: http://www.swffix.org/testsuite/ -->
251
+ <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" height="31" width="56">
252
+ <param name="movie" value="http://gzip.static.woot.com/Flash/SoundPlayer.swf?url=http://files.woot.com/20091102-p3y595.mp3" />
253
+ <param name="bgcolor" value="#91AB62" />
254
+ <!--[if !IE]>-->
255
+ <object type="application/x-shockwave-flash" data="http://gzip.static.woot.com/Flash/SoundPlayer.swf?url=http://files.woot.com/20091102-p3y595.mp3" height="31" width="56">
256
+ <param name="bgcolor" value="#91AB62" />
257
+ <!--<![endif]-->
258
+ <a href="http://files.woot.com/20091102-p3y595.mp3">Play</a>
259
+ <!--[if !IE]>-->
260
+ </object>
261
+ <!--<![endif]-->
262
+ </object>
263
+ </li>
264
+ <li class="title fn">
265
+ <a id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl01_HyperLinkTitle" rel="enclosure" type="audio/mpeg" href="http://files.woot.com/20091102-p3y595.mp3">On Four Years of the Woot Podcast</a>
266
+ </li>
267
+ </ul>
268
+ </div>
269
+ <div class="footer">
270
+ <ul class="clearfix">
271
+ <li class="discuss"><a id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl01_HyperLinkDiscuss" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554503">Discuss This Wootcast</a></li>
272
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl01_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554503">3 comments</a></li>
273
+ </ul>
274
+ </div>
275
+
276
+ </div>
277
+
278
+ <script type="text/javascript">
279
+ function showFullSaleStats()
280
+ {
281
+ // Only load sale stats one time per page load
282
+ if (jQuery('#fullSaleStats')[0].innerHTML.length == 0)
283
+ {
284
+ jQuery('#fullSaleStats').load('/SaleStats.aspx?wootsaleid=10457 #saleStats', null, function() { lightboxElement('fullSaleStats'); });
285
+ }
286
+ else
287
+ {
288
+ lightboxElement('fullSaleStats');
289
+ }
290
+ }
291
+ </script>
292
+ <div id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl02_PanelSaleStats" class="module saleStats">
293
+
294
+ <div class="header">
295
+ <h3><a href="javascript:showFullSaleStats();">Sale Stats Snapshot</a></h3>
296
+ <h4><a href="javascript:showFullSaleStats();">Full Stats</a></h4>
297
+ </div>
298
+ <div class="content">
299
+ <dl class="singleStats clearfix">
300
+
301
+ <dt>Speed to First Woot:</dt>
302
+ <dd>6m 59.973s</dd>
303
+
304
+
305
+ <dt>First Sucker:</dt>
306
+ <dd>laurie1933</dd>
307
+
308
+
309
+
310
+ </dl>
311
+ <h4>Quantity Breakdown</h4>
312
+ <ul class="horizontalBarChart">
313
+ <li><span class="value">85% bought 1</span><span class="bar" style="width:85%">85%</span></li>
314
+ <li><span class="value">10% bought 2</span><span class="bar" style="width:10%">10%</span></li>
315
+ <li><span class="value">5% bought 3</span><span class="bar" style="width:5%">5%</span></li>
316
+ </ul>
317
+ </div>
318
+ <div class="footer">
319
+ <p><a href="javascript:showFullSaleStats();">Full Stats &rarr;</a></p>
320
+ </div>
321
+
322
+ </div>
323
+ <div class="statsBoxOuter" id="fullSaleStats"></div>
324
+
325
+ <div id="ctl00_ctl00_ContentPlaceHolderMainContent_ContentPlaceHolderMainContent_ctl02_ctl03_PanelAdvertisement" class="module advertisement">
326
+
327
+ <div class="content">
328
+ <script type="text/javascript">GA_googleFillSlot('woot-homeside2-300x250');</script>
329
+ </div>
330
+ <div class="footer">
331
+ <p><a href="SponsorUs.aspx">Advertisement</a></p>
332
+ </div>
333
+
334
+ </div>
335
+ </div>
336
+ <p class="backToTop"><a href="#header">Back to top</a></p>
337
+
338
+
339
+ </div>
340
+ <div class="sidebar">
341
+
342
+
343
+
344
+ <script type="text/javascript">
345
+ // Google Analytics variables
346
+ var serverHour = 1;
347
+ var isWootOff = false;
348
+ </script>
349
+
350
+ <div class="module onOtherWoots">
351
+ <div class="content">
352
+ <div class="otherWootSite firstWoot">
353
+ <h3><a class="kids" href="http://kids.woot.com">Kids.Woot</a></h3>
354
+ <a href="http://kids.woot.com"><img alt="Luv n' Care Fleece Baby Blankets - 6 Pack" src="http://sale.images.woot.com/Luv_n__Care_Fleece_Baby_Blanket_Assorted_6_PackkumThumbnail.jpg" /></a>
355
+ </div>
356
+ <div class="otherWootSite lastWoot">
357
+ <h3><a class="shirt" href="http://shirt.woot.com">Shirt.Woot</a></h3>
358
+ <a href="http://shirt.woot.com"><img alt="The Spoilers Of Winter" src="http://sale.images.woot.com/x800Thumbnail.png" /></a>
359
+ </div>
360
+ </div>
361
+ </div>
362
+
363
+ <div class="module onOtherWoots">
364
+ <div class="content">
365
+ <div class="otherWootSite firstWoot">
366
+ <h3><a class="sellout" href="http://sellout.woot.com">Sellout.Woot</a></h3>
367
+ <a href="http://sellout.woot.com"><img alt="Sharper Image 24&quot; Rolling Duffle Bag" src="http://sale.images.woot.com/_Sharper_Image_24__Rolling_Duffle_BagdncThumbnail.jpg" /></a>
368
+ </div>
369
+ <div class="otherWootSite lastWoot">
370
+ <h3><a class="wine" href="http://wine.woot.com">Wine.Woot</a></h3>
371
+ <a href="http://wine.woot.com"><img alt="St. Supery Vineyards &#201;lu - 375ml - Three Pack" src="http://sale.images.woot.com/St._Supery_Vineyards_Élu__-_3_Pack3vyThumbnail.jpg" /></a>
372
+ </div>
373
+ </div>
374
+ </div>
375
+
376
+ <div class="module sideDeal">
377
+ <div class="header">
378
+ <h3><a href="SponsorUs.aspx" id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl02_SideDealLink">Today's Side Deal</a></h3>
379
+ </div>
380
+ <div class="content">
381
+ <p><p>Gateway Bluetooth laser mouse OEM <br />
382
+ only $7.99 over @ <a href="http://www.woot.com/3lq.r?url=http%3a%2f%2fwww.cowboom.com%2fdeal-of-the-day.cfm%3faff%3dwoot">CowBoom</a></p></p>
383
+ </div>
384
+ <div class="footer">
385
+ <ul class="clearfix">
386
+ <li class="discuss"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl02_HyperLinkDiscuss" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554499">Discuss This Side Deal</a></li>
387
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl02_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554499">0 comments</a></li>
388
+ </ul>
389
+ </div>
390
+ </div>
391
+
392
+
393
+ <div class="module blog">
394
+ <div class="header">
395
+ <h3><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_HyperLinkHeader" href="Blog/">Woot Blog</a></h3>
396
+ <h4><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_HyperLinkFeed" href="Blog/Feed.ashx">RSS Feed</a></h4>
397
+ </div>
398
+ <div class="content">
399
+
400
+ <ul class="clearfix firstPost">
401
+ <li class="date">Nov 02</li>
402
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9846">Of Course, If You WANT To Pay Us To Hype You…</a></li>
403
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl00_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3554057">3 comments</a></li>
404
+ </ul>
405
+
406
+ <ul class="clearfix ">
407
+ <li class="date">Oct 30</li>
408
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9829">Wootcasts from the Past: All Hallow’s Eve Edition</a></li>
409
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl01_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3549210">3 comments</a></li>
410
+ </ul>
411
+
412
+ <ul class="clearfix ">
413
+ <li class="date">Oct 29</li>
414
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9823">The Monster Mashup: Great Halloween Hits</a></li>
415
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl02_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3547872">8 comments</a></li>
416
+ </ul>
417
+
418
+ <ul class="clearfix ">
419
+ <li class="date">Oct 29</li>
420
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9821">Flash In The Brainpan: Red Remover</a></li>
421
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl03_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3547803">7 comments</a></li>
422
+ </ul>
423
+
424
+ <ul class="clearfix ">
425
+ <li class="date">Oct 28</li>
426
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9729">Real Actual Field Tests #3: Superman Inflato-Suit</a></li>
427
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl04_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3537168">20 comments</a></li>
428
+ </ul>
429
+
430
+ <ul class="clearfix ">
431
+ <li class="date">Oct 26</li>
432
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9585">10 Hot Rumors About Tomorrow's Ares Rocket Test Launch</a></li>
433
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl05_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3525409">12 comments</a></li>
434
+ </ul>
435
+
436
+ <ul class="clearfix ">
437
+ <li class="date">Oct 22</li>
438
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9565">Wootcasts from the Past: Magellan Like a Felon Edition</a></li>
439
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl06_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3518491">5 comments</a></li>
440
+ </ul>
441
+
442
+ <ul class="clearfix ">
443
+ <li class="date">Oct 22</li>
444
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9563">Windows 7 FAQ Or...Something Else?</a></li>
445
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl07_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3518355">11 comments</a></li>
446
+ </ul>
447
+
448
+ <ul class="clearfix ">
449
+ <li class="date">Oct 21</li>
450
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9557">Dancers Must Be At Least Ten Hours Old: Woot Weads The Wire</a></li>
451
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl08_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3517243">1 comment</a></li>
452
+ </ul>
453
+
454
+ <ul class="clearfix ">
455
+ <li class="date">Oct 21</li>
456
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9556">14 Amazing New Mac Features That Apple Forgot To Mention</a></li>
457
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_RepeaterNews_ctl09_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3516836">23 comments</a></li>
458
+ </ul>
459
+
460
+ </div>
461
+ <div class="footer">
462
+ <p><a href="Blog/" id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl04_SeeAllLink">See All &rarr;</a></p>
463
+ </div>
464
+ </div>
465
+ <div id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl05_PanelAdvertisement" class="module advertisement">
466
+
467
+ <div class="content">
468
+ <script type="text/javascript">GA_googleFillSlot('woot-homeside3-300x250');</script>
469
+ </div>
470
+ <div class="footer">
471
+ <p><a href="SponsorUs.aspx">Advertisement</a></p>
472
+ </div>
473
+
474
+ </div>
475
+
476
+ <div class="module blog">
477
+ <div class="header">
478
+ <h3><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl06_HyperLinkHeader" href="Blog/?cat=Contest">Woot Contests</a></h3>
479
+ <h4><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl06_HyperLinkFeed" href="Blog/Feed.ashx?cat=Contest">RSS Feed</a></h4>
480
+ </div>
481
+ <div class="content">
482
+
483
+ <ul class="clearfix firstPost">
484
+ <li class="date">Oct 28</li>
485
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9655">Winners' Gallery: the Best of Contest 232</a></li>
486
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl06_RepeaterNews_ctl00_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3536801">10 comments</a></li>
487
+ </ul>
488
+
489
+ <ul class="clearfix ">
490
+ <li class="date">Oct 27</li>
491
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9654">Winners' Gallery: the Best of Contest 231</a></li>
492
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl06_RepeaterNews_ctl01_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3529204">19 comments</a></li>
493
+ </ul>
494
+
495
+ <ul class="clearfix ">
496
+ <li class="date">Oct 19</li>
497
+ <li class="title"><a href="http://www.woot.com/Blog/ViewEntry.aspx?Id=9544">Woot Contest 237: Deflating The Conspiracy</a></li>
498
+ <li class="comments"><a id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl06_RepeaterNews_ctl02_HyperLinkComments" href="http://www.woot.com/Forums/ViewPost.aspx?PostID=3513628">53 comments</a></li>
499
+ </ul>
500
+
501
+ </div>
502
+ <div class="footer">
503
+ <p><a href="Blog/" id="ctl00_ctl00_ContentPlaceHolderSidebar_ContentPlaceHolderSidebar_ctl00_ctl06_SeeAllLink">See All &rarr;</a></p>
504
+ </div>
505
+ </div>
506
+
507
+
508
+
509
+ </div>
510
+ </div>
511
+ <div id="footerWrapper">
512
+ <div id="footer">
513
+
514
+
515
+ <div id="ctl00_ctl00_ContentPlaceHolderFooter_ContentPlaceHolderFooter_ctl00_PanelFooterAdditionalNav">
516
+
517
+ <div class="footerSeparator"></div>
518
+ <div class="linkFooter">
519
+ <div class="mumbo">
520
+ <h5><a href="/Terms.aspx">Mumbo Jumbo</a></h5>
521
+ <p>
522
+ Product narratives are for entertainment purposes and frequently employ <a href="http://en.wikipedia.org/wiki/Point_of_view_(literature)">literary point of view</a>; the narratives do not express Woot's editorial opinion.
523
+ Aside from literary abuse, your use of this site also subjects you to Woot's <a href="/Terms.aspx">terms of use</a> and <a href="/User/PrivacyNotice.aspx">privacy policy</a>.
524
+ </p>
525
+ <p>Woot logos, site design, &amp; content &copy; Woot, Inc. 2004-2009. All Rights Reserved.</p>
526
+ </div>
527
+ <div class="linkCol footerGutter">
528
+ <h5><a href="/">Woot</a></h5>
529
+ <ul>
530
+ <li><a href="/">Today's Woot</a></li>
531
+ <li><a href="/Blog/">Blog</a></li>
532
+ <li><a href="/Forums/">Community</a></li>
533
+ <li><a href="/WriteUs.aspx">Write Us</a></li>
534
+ <li><a href="/WhatIsWoot.aspx">What is Woot?</a></li>
535
+ </ul>
536
+ </div>
537
+ <div class="linkCol">
538
+ <h5><a href="/Blog/">Blog</a></h5>
539
+ <ul>
540
+ <li><a href="/Blog/?cat=Woot">Woot</a></li>
541
+ <li><a href="/Blog/?cat=News">News</a></li>
542
+ <li><a href="/Blog/?cat=Contest">Contest</a></li>
543
+ <li><a href="/Blog/?cat=Laffs">Laffs</a></li>
544
+ <li><a href="/Blog/?cat=Miscellanea">Miscellanea</a></li>
545
+ </ul>
546
+ </div>
547
+ <div class="linkCol">
548
+ <h5><a href="/Forums/">Community</a></h5>
549
+ <ul>
550
+ <li><a href="/Forums/">Woots</a></li>
551
+ <li><a href="/Forums/ViewForum.aspx?ForumID=15">World of Woot</a></li>
552
+ <li><a href="/Forums/ViewForum.aspx?ForumID=16">Contests</a></li>
553
+ <li><a href="/Forums/ViewForum.aspx?ForumID=21">Woot Side Deals</a></li>
554
+ <li><a href="/Forums/ViewForum.aspx?ForumID=17">Everything But Woot</a></li>
555
+ </ul>
556
+ </div>
557
+ <div class="linkCol">
558
+ <h5><a href="/WhatIsWoot.aspx">What Is Woot?</a></h5>
559
+ <ul>
560
+ <li><a href="/WhatIsWoot.aspx">Woot FAQ</a></li>
561
+ <li><a href="/SponsorUs.aspx">Be a Woot Sponsor</a></li>
562
+ <li><a href="/Jobs.aspx">Work for Woot</a></li>
563
+ <li><a href="/Recalls.aspx">Product Recall Notices</a></li>
564
+ <li><a href="/Terms.aspx">Terms and Conditions</a></li>
565
+ <li><a href="/User/PrivacyNotice.aspx">Privacy Policy</a></li>
566
+ </ul>
567
+ </div>
568
+ </div>
569
+
570
+ </div>
571
+
572
+
573
+ </div>
574
+ </div>
575
+ </div>
576
+ </form>
577
+ <!--[if IE 6]>
578
+ <script type="text/javascript" src="http://gzip.static.woot.com/Scripts/mtjs_iepnghandler_solo.min.5034.js"></script>
579
+ <script type="text/javascript">$(document).ready(function() { mtjs_iepnghandler_solo.go(); });</script>
580
+ <![endif]-->
581
+ <script type="text/javascript">
582
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
583
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
584
+ </script>
585
+ <script type="text/javascript">
586
+ var pageTracker = _gat._getTracker('UA-31798-1');
587
+ pageTracker._initData();
588
+ pageTracker._trackPageview('%2fdefault.aspx');
589
+ </script>
590
+ <!-- Start Quantcast tag -->
591
+ <script type="text/javascript">
592
+ _qoptions = { qacct: "p-45WWkjSYwI3II" };
593
+ </script>
594
+ <script type="text/javascript">
595
+ var quantcastHost = (("https:" == document.location.protocol) ? "https://secure." : "http://edge.");
596
+ document.write(unescape("%3Cscript src='" + quantcastHost + "quantserve.com/quant.js' type='text/javascript'%3E%3C/script%3E"));
597
+ </script>
598
+ <noscript>
599
+ <img src="https://secure.quantserve.com/pixel/p-45WWkjSYwI3II.gif" style="display:none;" border="0" height="1" width="1" alt="Quantcast" />
600
+ </noscript>
601
+ <!-- End Quantcast tag -->
602
+ </body>
603
+ </html>
@@ -1,5 +1,6 @@
1
- require 'rubygems'
2
1
  require 'test/unit'
2
+ require 'rubygems'
3
+ require 'fakeweb'
3
4
  require 'shoulda'
4
5
 
5
6
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
@@ -16,8 +17,74 @@ class Test::Unit::TestCase
16
17
  @possible_blank_attributes ||= [:purchase_url]
17
18
  end
18
19
 
20
+ def self.fixtures
21
+ @fixtures ||= Dir[File.join(File.dirname(__FILE__), 'fixtures', '*.html')].inject({}) { |hash, file| hash.merge! File.basename(file).gsub(/\.html$/, '') => file }
22
+ end
23
+
24
+ def self.register_fakeweb_uris
25
+ fixtures.each { |subdomain, file| FakeWeb.register_uri(:get, "http://#{subdomain}.#{Woot::DOMAIN}/", :body => File.read(file)) }
26
+ end
27
+
19
28
  def self.woots
20
- @woots ||= Woot::SUBDOMAINS.inject({}) { |hash, subdomain| hash.merge! subdomain => Woot.scrape(subdomain) }
29
+ @woots ||= (Woot::SUBDOMAINS + fixtures.keys).inject({}) { |hash, subdomain| hash.merge! subdomain => Woot.scrape(subdomain) }
21
30
  end
22
31
 
23
- end
32
+ register_fakeweb_uris
33
+
34
+ end
35
+
36
+ class MockTwitterStatus
37
+
38
+ attr_reader :id, :text
39
+
40
+ def initialize(id, text = '')
41
+ @id = id
42
+ @text = text
43
+ end
44
+
45
+ def user
46
+ self
47
+ end
48
+
49
+ end
50
+
51
+ WOOT_FIXTURE_VALUES = {
52
+ 'available' => {
53
+ :subdomain => 'available',
54
+ :title => 'Blockade Noise Isolating Earbuds - 2 Pack',
55
+ :price => '14.99',
56
+ :currency => 'USD',
57
+ :currency_symbol => '$',
58
+ :shipping => "\n+ $5 shipping\n",
59
+ :image => 'http://sale.images.woot.com/Blockade_Noise_Isolating_EarbudsmqlStandard.jpg',
60
+ :alternate_image => 'http://sale.images.woot.com/Blockade_Noise_Isolating_Earbudsqx4Detail.jpg',
61
+ :url => 'http://www.woot.com/sale/10457',
62
+ :comments_url => 'http://www.woot.com/Forums/ViewPost.aspx?PostID=3554500',
63
+ :comments_count => '71',
64
+ :header => 'I think the little hairy guy with the claws is popping my bike tires on purpose',
65
+ :subheader => 'Head down, earbuds in, try not to get hit by a laser',
66
+ :writeup => "\nMy mother-in-law thought we were crazy. &ldquo;You two are going to end up pulverized by a giant world-eating alien just like your Aunt Regina!&rdquo; We&rsquo;ve always wanted to live in Metro City, though, and when Jessica got that job offer at the Major Daily Newspaper, we were excited to move to where all the costumed action is.\nFor about the first three weeks, anyway.\nWhen the errant meteorite hit the Volvo, we shrugged it off and started using public transportation. Then, our dog Scamp was eaten by the Crimson Cowl&rsquo;s cyborg velociraptors. And around the fourth time some villain&rsquo;s robot henchman gets plowed through your wall and into your living room without so much as a &ldquo;Sorry, Citizens&rdquo; from whatever hero happens to be on duty that day, you start to get a little annoyed.\nI&rsquo;m not complaining, really. That&rsquo;s what cape insurance is for, after all. That&rsquo;s the price you pay for living in the superhero capital of the world, I guess. You either pack your things and move to Wyoming, or you learn to adapt. It just takes a little adjusting.\nSo on the nights when the sky burns red with crisis or some silver-plated intergalactic herald is preaching doom and gloom all over the city, my wife and I plug the Blockade Noise Isolating Earbuds into our MP3 players. The triple flange design provides optimal noise protection from all the laser blasts and explosions that flood the city soundscape, allowing us to concentrate on the music or audiobook we&rsquo;re listening to. When I need to take a trip down to the corner market and have to jump out of the way of an automobile being thrown by some hulking gamma-irradiated scientist, the comfortable fit of these earbuds means the music stays in my ears. The integrated volume control in the cord is great for when I want to drown out any superhero bellowing witty banter, too.\nIf anyone knows a good way of keeping some of these heroes from perching on the gargoyle outside our bedroom window at night, though, I&rsquo;d love to hear it. I know they&rsquo;re just doing their inner-monologue thing, but it gets kinda creepy.\n",
67
+ :specs => "\n\nWarranty: 90 Day Woot Limited Warranty\nFeatures:\n\nPatented triple-flange ear bud design provides optimal noise protection for an excellent fit that radically reduces noise\nIntegrated volume control places fingertip adjustment of any iPod or MP3 player easily within reach\n24 decibel Noise Reduction Rating brings an end to dangerously over-cranked tunes struggling to compete with loud external sounds\nUse in the yard while mowing and gardening, in the workshop, on the job, in the gym or traveling on a plane to safely isolate background noise\nUltra comfortable design from the same company who brought you the industry leading WorkTunes\niPod and MP3 compatible (any device with a 3.5mm plug)\nMeets ANSI/OSHA Standards\n\nAdditional Photos:\n\nBlockade Noise Isolating Earbuds\nVolume Control\nTriple-flange ear bud design\n\nIn the box:\n\n2 AO Safety 99014 Blockade Noise Isolating Earbuds\n6 Extra Pairs of Ear Tips\n2 Carrying Bags\n\n",
68
+ :details => "\nCondition:\nNew\nProduct:\n2 AO Safety 99014 Blockade Noise Isolating Earbuds\n",
69
+ :purchase_url => 'http://available.woot.com/WantOne.aspx?id=983db0c6-5c69-4737-926b-3697d4af542e'
70
+ },
71
+ 'soldout' => {
72
+ :subdomain => 'soldout',
73
+ :title => 'iRobot Roomba 530 Robotic Vacuum with Virtual Wall',
74
+ :price => '129.99',
75
+ :currency => 'USD',
76
+ :currency_symbol => '$',
77
+ :shipping => "\n+ $5 shipping\n",
78
+ :image => 'http://sale.images.woot.com/iRobot_Roomba_530_Robotic_Vacuum_with_Virtual_WalluquStandard.jpg',
79
+ :alternate_image => 'http://sale.images.woot.com/iRobot_Roomba_530_Robotic_Vacuum_with_Virtual_WallyxlDetail.jpg',
80
+ :url => 'http://www.woot.com/sale/10244',
81
+ :comments_url => 'http://www.woot.com/Forums/ViewPost.aspx?PostID=3553042',
82
+ :comments_count => '209',
83
+ :header => 'Looking For Mr. Roombar',
84
+ :subheader => 'This is nice, isn&rsquo;t it? I have to say, I was surprised when you called me. Most people who date robots prefer the kind that, you know, look like people.',
85
+ :writeup => "\nI just keep thinking about all those times you came over to play cards with Len and Sherry. Of course I noticed you, but I never imagined you noticed me, way down on the floor in my self-charging home base. Well, there was this one time when I heard you ask Sherry about me. It made my heart leap. But then Sherry just started talking about how convenient I was, and how my counter-rotating Bristle Brush and Beater Brush work together like a broom and dustpan to lift hair, dust, and debris out of carpet. I just assumed you were interested in my cleaning abilities, not me personally. Glad I was wrong!\nWow, everything on the menu looks so good. I&rsquo;d heard about this place, but it&rsquo;s even nicer than I imagined. Well, except for the floors. It&rsquo;s like they think they can slap down a brown carpet and forget about ever vacuuming again. Well, they can&rsquo;t fool me and my Dirt Detect capability. Like that smear of, like, dried holladaise sauce or whatever it is, over by that booth. See, if it was up to me, I&rsquo;d really bear down with my Spot Clean mode, and I&rsquo;d have that crud lifted up before you could say &ldquo;new, improved filter&rdquo;. See, that&rsquo;s the difference between me and a regular old-\nListen to me. Talking shop in the middle of a lovely first date. Sorry. I just don&rsquo;t get out much.\nSo, uh, have you seen any interesting movies lately? I haven&rsquo;t. I&rsquo;ve actually never seen a movie in a theater. Every time I try, I see all that popcorn and all those crumbs all over the floor, and I just can&rsquo;t resist getting down there and sweeping it all up. Well, you can imagine the noise. I&rsquo;m loud, I know. What can I say? I grew up in a loud family. You get us together, it&rsquo;s VRRRR-VRRRR-VRRRR the whole time.\nWhat? Go back to your place? Sure. Yeah, that would be fun. I&rsquo;m not that hungry anyway. Um, yes, I did bring my Virtual Wall. Yeah, I emptied my Debris Bin right before you picked me up. Why do you ask?\nOh. Oh, I see. So it&rsquo;s like that. I guess I should&rsquo;ve known.\n",
86
+ :specs => "Authorized for SquareTrade Extended Warranty\n\n\n\n//<![CDATA[\n$(document).ready(function() {st_widget.create({itemCondition:'Refurbished',itemDescription:'iRobot Roomba 530 Robotic Vacuum with Virtual Wall',itemPrice:'129.99',bannerStyle:'wide',widgetType:'quote',merchantID:'subscrip_014793207843'}); });\n//\n\n\nWarranty: 90 Day iRobot\nFeatures:\n\nEfficiently vacuums dirt, debris, pet hair, dust, allergens and more from carpets and hard floors\nCounter rotating Bristle Brush and Beater Brush work together like a dustpan and broom\nSturdy Bristle Brush digs deep into carpet fibers to grab dirt, debris, pet hair and more\nPowerful vacuum sucks large and small debris into the large, bag-less bin\nFine filter traps dust, pollen and tiny particulate inside the bin\nCleans the whole floor, under and around furniture, into corners and along wall edges\nDetects dirtier areas and spends more time cleaning them\nSpot Clean provides quick clean-up of spills and concentrated messes\nAutomatically senses and avoids stairs and other drop-offs\nSimple operation&mdash;just press the Clean button and Roomba does the rest\nAutomatically returns to its self-charging Home Base&reg; to dock and recharge between cleanings\nFaster counter-rotating brushes with improved design pick up more hair and debris and are easier to remove and clean\nImproved filter captures more dust and allergens while a larger bin holds more debris\nImproved anti-tangle technology keeps Roomba from getting stuck on cords, carpet fringe and tassels\nImproved sidebrush makes Roomba even more efficient at cleaning edges and corners\n\nAdditional Photo:\n\nUnderbelly\nIn Home Base with Virtual Wall\nVirtual Wall\n\nIn the box:\n\n1 iRobot Roomba 530\n1 Virtual Wall&nbsp;\n1 Self-charging Home Base\n1 Power Supply (3 hour charge time)\n1 Rechargeable Battery\n1 Filter\n\n&nbsp;\n",
87
+ :details => "\nCondition:\nRefurbished\nProduct:\n1 iRobot Roomba 530 Robotic Vacuum with Virtual Wall and Self-Charging Home Base\n",
88
+ :purchase_url => nil
89
+ }
90
+ }
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class WootTest < Test::Unit::TestCase
4
-
4
+
5
5
  woots.each do |subdomain, woot|
6
6
  context "When parsing http://#{subdomain}.#{Woot::DOMAIN}/ it" do
7
7
  attributes.each do |attribute|
@@ -19,4 +19,38 @@ class WootTest < Test::Unit::TestCase
19
19
  end
20
20
  end
21
21
 
22
+ context 'When parsing the fixture' do
23
+ fixtures.each do |subdomain, file|
24
+ context "for http://#{subdomain}.#{Woot::DOMAIN} it" do
25
+ attributes.each do |attribute|
26
+ should "parse the correct value for #{attribute}" do
27
+ assert_equal WOOT_FIXTURE_VALUES[subdomain][attribute], self.class.woots[subdomain].send(attribute)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'When calling the subdomain_from_twitter_status method it' do
35
+ should 'return nil if the user id is not included in Woot::SUBDOMAINS' do
36
+ # Sometimes the Twitter stream may return @woot replies from other users which we don't need
37
+ assert_nil Woot.send(:subdomain_from_twitter_status, MockTwitterStatus.new(99999999))
38
+ end
39
+
40
+ should 'return the associated subdomain if the user id is included in Woot::SUBDOMAINS' do
41
+ Woot::SUBDOMAINS.reject { |subdomain| subdomain == Woot::WOOT_OFF }.each do |subdomain|
42
+ assert_equal subdomain, Woot.send(:subdomain_from_twitter_status, MockTwitterStatus.new(Woot::TWITTER_IDS[subdomain]))
43
+ end
44
+ end
45
+
46
+ should 'return the associated subdomain from the url in the status if it comes from the woot-off user' do
47
+ assert_equal 'www', Woot.send(:subdomain_from_twitter_status, MockTwitterStatus.new(Woot::TWITTER_IDS[Woot::WOOT_OFF], "blah blah blah http://www.#{Woot::DOMAIN}"))
48
+ assert_equal 'shirt', Woot.send(:subdomain_from_twitter_status, MockTwitterStatus.new(Woot::TWITTER_IDS[Woot::WOOT_OFF], "blah blah blah shirt.#{Woot::DOMAIN} blah blah"))
49
+ end
50
+
51
+ should 'return nil if the status comes from the woot-off user without a woot url in it' do
52
+ assert_nil Woot.send(:subdomain_from_twitter_status, MockTwitterStatus.new(Woot::TWITTER_IDS[Woot::WOOT_OFF], 'blah blah blah'))
53
+ end
54
+ end
55
+
22
56
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{woot}
8
- s.version = "0.0.6"
8
+ s.version = "0.0.7"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sean Huber"]
12
- s.date = %q{2009-11-02}
12
+ s.date = %q{2009-11-03}
13
13
  s.description = %q{Scapes woot.com sites}
14
14
  s.email = %q{shuber@huberry.com}
15
15
  s.extra_rdoc_files = [
@@ -21,9 +21,9 @@ Gem::Specification.new do |s|
21
21
  "README.rdoc",
22
22
  "Rakefile",
23
23
  "VERSION",
24
- "init.rb",
25
24
  "lib/woot.rb",
26
- "test/fixtures/sold_out.html",
25
+ "test/fixtures/available.html",
26
+ "test/fixtures/soldout.html",
27
27
  "test/test_helper.rb",
28
28
  "test/woot_test.rb",
29
29
  "woot.gemspec"
@@ -45,15 +45,18 @@ Gem::Specification.new do |s|
45
45
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
46
  s.add_runtime_dependency(%q<scrapi>, [">= 0"])
47
47
  s.add_runtime_dependency(%q<tweetstream>, [">= 0"])
48
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
48
49
  s.add_development_dependency(%q<shoulda>, [">= 0"])
49
50
  else
50
51
  s.add_dependency(%q<scrapi>, [">= 0"])
51
52
  s.add_dependency(%q<tweetstream>, [">= 0"])
53
+ s.add_dependency(%q<fakeweb>, [">= 0"])
52
54
  s.add_dependency(%q<shoulda>, [">= 0"])
53
55
  end
54
56
  else
55
57
  s.add_dependency(%q<scrapi>, [">= 0"])
56
58
  s.add_dependency(%q<tweetstream>, [">= 0"])
59
+ s.add_dependency(%q<fakeweb>, [">= 0"])
57
60
  s.add_dependency(%q<shoulda>, [">= 0"])
58
61
  end
59
62
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: woot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Huber
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-02 00:00:00 -08:00
12
+ date: 2009-11-03 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,16 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: "0"
34
34
  version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: fakeweb
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
35
45
  - !ruby/object:Gem::Dependency
36
46
  name: shoulda
37
47
  type: :development
@@ -56,9 +66,9 @@ files:
56
66
  - README.rdoc
57
67
  - Rakefile
58
68
  - VERSION
59
- - init.rb
60
69
  - lib/woot.rb
61
- - test/fixtures/sold_out.html
70
+ - test/fixtures/available.html
71
+ - test/fixtures/soldout.html
62
72
  - test/test_helper.rb
63
73
  - test/woot_test.rb
64
74
  - woot.gemspec
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require 'woot'