Class variables in Ruby on Rails (05 may 09)
Rails has a cute method, cattr_accessor, which creates class-wide variables
These variables begin with '@@' and are for storing things you only need one of across your whole application
My http://pdxspurs.com has a 'News' section which uses the Guardian Ruby API to search the files of the Guardian newspaper in London for news about football - http://www.guardian.co.uk/open-platform
It takes a while to search, and the news doesn't change very often, so I wanted to set it up so the news is only gotten once per day
I store the date, and if the date has changed since the last time anyone looked at the news, I get new news
The funny thing is, it didn't work in development - it always reloaded the news, even if the date hadn't changed
I figured out why - all code is reloaded in development mode every time you hit 'Reload' in your browser
This means that the class-wide variables were reset, so the code thought the date was new every time
So I ran it in production mode, and t worked - it only loaded the news once
I guess I'll have to wait 'til tomorrow to find out if it really worked, but here's the code, guardian.rb:
# Part of the Guardian API require 'custodian' # sudo gem install libxml-ruby require 'xml/libxml'
class Guardian ONE_DAY = 60 * 60 * 24 NUM_DAYS_BACK = 4 HEAD = "//content/headline" BODY = "//content/type-specific/body" DATE = "//content/publication-date" ENDING = "\n</content>" MAX_RESULTS = '25' cattr_accessor :results # Create @@results and @@last_time_got cattr_accessor :last_time_got # Formats date num_days ago: 'Sun Oct 05 11:00 2008' -> '20081005' def Guardian.display_date(num_days) t = Time.now - (num_days * ONE_DAY) d = t.to_s l = d.length y = d[l-4..l-1] d = d[8..9] m = t.month.to_s m = '0' + m if m.length < 2 y + m + d end def Guardian.result(which_one) Guardian.set_results which_one = rand(@@results.length) if which_one.nil? return @@results[which_one.to_i] end
def Guardian.results_html Guardian.set_results return 'No news is good news' if @@results.length < 1 html = '' i = 0 @@results.each do |r| arr = r.split("\n") tit = arr[0] tit.gsub!(' ', '') html += "<a href='" + "/news/" + i.to_s + "'>" + tit + "</a>" + "\n<br/>" i = i + 1 end return html end
private def Guardian.set_results Custodian.api_key = 'THIS IS A SECRET'
@@last_time_got = 'nil' if @@last_time_got.nil?
@date = Guardian.display_date( NUM_DAYS_BACK ) @@results = [] if @@results.nil? # Get new results just once every day return if @@results.length > 1 and @date == @@last_time_got @@last_time_got = @date @articles = Custodian::Article.find(:all, { :q => "Tottenham", :filter => '/football', :after => @date, :content_type => 'article', :count => MAX_RESULTS }) if @articles.length < 1 @@results = ["Well, they say no news is good news"] return end
@@results = [] xml_str = '' @articles.reverse.each do |a| begin # Correct the XML xml_str = a.xml.to_s xml_arr = xml_str.split("\n") # Strip off the Grauniad's incorrect ending - '</publication-date>...</content>' xml_arr.delete_at(xml_arr.length - 1) xml_str = xml_arr.join("\n") # Tack on the happy ending xml_str = xml_str + ENDING doc = XML::Parser.string( xml_str ).parse date = '' head = '' body = '' doc.find(HEAD).each do |node| head = node.content head = "<b>" + head + "</b>" end doc.find(DATE).each do |node| date = node.content date = "\n<br/><b>" + date[0..9] + "</b>" end doc.find(BODY).each do |node| body = node.content # Try to add some formatting body.gsub!( ". ", ".\n<br/><br/>") end @@results << head + date + "\n<br/><br/>" + body if not (body.strip.empty?)
rescue Exception => err @@results = [err.message] end end end
end
Back
Portland |
|
London |
|