Can't assign value to Variable: undefined method `[]' for nil:NilClass (NoMethodError) - ruby

I am completely stumped on this one.
I have the following code:
puts block.at_xpath("*/img")["width"].to_i
but when I change it to
width = block.at_xpath("*/img")["width"].to_i
I get this error:
NokogiriTUT.rb:70:in `blockProcessor': undefined method `[]' for nil:NilClass (NoMethodError)
When I have the puts in there it returns the expected value.
Update:
def blockProcessor(block)
header = block.xpath('td[#class="default"]/*/span[#class="comhead"]')
array = header.text.split
if array[0] != nil #checks to make sure we aren't at the top of the parent list
### Date and Time ###
if array[2] == 'hours' || array[2] == 'minutes'
date = Time.now
else
days = (array[1].to_i * 24 * 60 * 60)
date = Time.now - days
end
##Get Comment##
comment = block.at_xpath('*/span[#class="comment"]')
hash = comment.text.hash
#puts hash
##Manage Parent Here##
width = block.at_xpath("*/img")["width"].to_i
prevlevel = #parent_array[#parent_array.length-1][1]
if width == 0 #has parents
parentURL = header.xpath('a[#href][3]').to_s
parentURL = parentURL[17..23]
parentURL = "http://news.ycombinator.com/item?id=#{parentURL}"
parentdoc = Nokogiri::HTML(open(parentURL))
a = parentdoc.at_xpath("//html/body/center/table/tr[3]/td/table/tr")
nodeparent = blockProcessor(a)
#parent_array = []
node = [hash, width, nodeparent] #id, level, parent
#parent_array.push node
elsif width > prevlevel
nodeparent = #parent_array[#parent_array.length-1][0]
node = [hash, width, nodeparent]
#parent_array.push node
elsif width == prevlevel
nodeparent = #parent_array[#parent_array.length-1][2]
node = [hash, width, nodeparent]
#parent_array.push node
elsif width < prevlevel
until prevlevel == w do
#parent_array.pop
prevlevel = #parent_array[#parent_array.length-1][1]
end
nodeparent = #parent_array[#parent_array.length-1][2]
node = [hash, width, nodeparent]
#parent_array.push node
end
puts "Author: #{array[0]} with hash #{hash} with parent: #{nodeparent}"
##Handles Any Parents of Existing Comments ##
return hash
end
end
end
Here is the block that it is acting on.
<tr>
<td><img src="http://ycombinator.com/images/s.gif" height="1" width="0"></td>
<td valign="top"><center>
<a id="up_3004849" href="vote?for=3004849&dir=up&whence=%2f%78%3f%66%6e%69%64%3d%34%6b%56%68%71%6f%52%4d%38%44"><img src="http://ycombinator.com/images/grayarrow.gif" border="0" vspace="3" hspace="2"></a><span id="down_3004849"></span>
</center></td>
<td class="default">
<div style="margin-top:2px; margin-bottom:-10px; "><span class="comhead">patio11 12 days ago | link | parent | on: Ask HN: What % of your job interviewees pass FizzB...</span></div>
<br><span class="comment"><font color="#000000">Every time FizzBuzz problems come up among engineers, people race to solve them and post their answers, then compete to see who can write increasingly more nifty answers for a question which does not seek niftiness at all.<p>I'm all for intellectual gamesmanship, but these are our professional equivalent of a doctor being asked to identify the difference between blood and water. You can do it. <i>We know</i>. Demonstrating that you can do it is not the point of the exercise. We do it to have a cheap-to-administer test to exclude people-who-cannot-actually-program-despite-previous-job-titles from the expensive portions of the hiring process.</p></font></span><p><font size="1"><u>reply</u></font></p>
</td>
</tr>

Your basic problem is that you don't understand XPath. (You are in good company there; XPath is quite confusing.) Your selectors simply don't match what you think they match. In particular, the one that blows up
*/img
should be
//img
or something like that.
Now, because the xpath selector doesn't match anything, the value of this Ruby statement
block.at_xpath("*/img")
is nil. And nil doesn't support [], so when you try to call ["width"] on it, Ruby complains with a undefined method [] for nil:NilClass error.
And as for why it only blows up when you assign it to a variable... yeah, that's not actually what's happening. You probably changed something else too.
And now, please allow me to make some other hopefully constructive code criticisms:
Your question was apparently designed to make it difficult to answer. In the future, please isolate the code in question, don't just paste in your whole homework assignment (or whatever this screen scraper is for).
It would be extra great if you made it into a single runnable Ruby file that we can execute verbatim on our computers, e.g.:
.
require "nokogiri"
doc = Nokogiri.parse <<-HTML
<tr>
<td><img src="http://ycombinator.com/images/s.gif" height="1" width="0"></td>
<td valign="top"><center>
<a id="up_3004849" href="vote?for=3004849&dir=up&whence=%2f%78%3f%66%6e%69%64%3d%34%6b%56%68%71%6f%52%4d%38%44"><img src="http://ycombinator.com/images/grayarrow.gif" border="0" vspace="3" hspace="2"></a><span id="down_3004849"></span>
</center></td>
<td class="default">
<div style="margin-top:2px; margin-bottom:-10px; ">
<span class="comhead">
patio11 12 days ago | link | parent | on: Ask HN: What % of your job interviewees pass FizzB...
</span>
</div>
<br><span class="comment"><font color="#000000">Every time FizzBuzz problems come up among engineers, people race to solve them and post their answers, then compete to see who can write increasingly more nifty answers for a question which does not seek niftiness at all.<p>I'm all for intellectual gamesmanship, but these are our professional equivalent of a doctor being asked to identify the difference between blood and water. You can do it. <i>We know</i>. Demonstrating that you can do it is not the point of the exercise. We do it to have a cheap-to-administer test to exclude people-who-cannot-actually-program-despite-previous-job-titles from the expensive portions of the hiring process.</p></font></span><p><font size="1"><u>reply</u></font></p>
</td>
</tr>
HTML
width = doc.at_xpath("*/img")["width"].to_i
That way we can debug with our computers, not just with our minds.
You're writing Ruby now, not Java, so conform to Ruby's spacing and naming conventions: file names are snake_case, indentation is 2 spaces, no tabs, etc. It really is difficult to read code that's formatted wrong -- where "wrong" means "non-standard."
Everywhere you have one of those descriptive comments (### Date and Time ###) is an opportunity to extract a method (def date_and_time(array)) and make your code cleaner and easier to debug.

Related

Ruby Dashing: Issues with Jobs (on a CentOS Server)

I'm having a weird event occur, where my dashing dashboard's list widget is showing erroneous data. Here's the screenshot from my live Dashing widget
Erroneous Widget
Expected Output
What follows is the code for the widget:
Code in .erb
<li data-row="1" data-col="1" data-sizex="2" data-sizey="6">
<div data-id="facebook_insights" data-view="List" data-unordered="true" data-title="Facebook Insights: Weekly Post Views" data-moreinfo="Updated every 10 seconds"</div>
</li>
Code in job .rb
require 'mysql2'
social_count = Hash.new({ value: 0 })
time = Time.new()
date_time1 = Time.new(time.year, time.month, time.day-1)
...
SCHEDULER.every '10s' do
begin
db = Mysql.new(<HOST>,<USER>,<PASS>,<DBNAME>)
mysql1 = "SELECT <VAR> FROM <TABLE> WHERE <VAR> = '#{date_time1}' ORDER BY <VAR> DESC LIMIT 1"
...
result1 = db.query(mysql1)
...
rescue
ensure
db.close
end
result1.each do |row|
strrow1 = row[0]
$value1 = strrow1.to_i
end
...
social_count[0] = {label: "1:", value: $value1}
...
send_event('facebook_insights', { items: social_count.values })
end
What is really baffling, is that this code works for a similar widget using different data in the SQL query. Can anyone help me understand why?
I checked and re-checked the data and in my other, working code, I had my $value variables defined as $valueX with X being the number. I thought to myself "Maybe the variable names are getting confused due to them having the same name", so I changed my code to
Working Code
result1.each do |row|
strrow1 = row[0]
$variable1 = strrow1.to_i
end
...
social_count[0] = {label: "1:", value: $variable1}
Et Voila! Eureka! It worked. Not sure why it still got confused with the names, but from now on, my names will be unique!

What do test automation frameworks provide that my approach of scripting with Selenium Webdriver doesn't?

I am a newbie to software test automation and have written the following test script in Selenium Webdriver and Ruby binding. It performs user actions (clicks, enters, fills up values etc.). I have put basic asserts that match the screen text value with value I provide. Below is the code:
puts "Test Run 1 has started ""["+Time.now.strftime('%H:%M:%S CST')+"]"
require "selenium-webdriver"
require "colorize"
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.cache.disk.enable'] = false
browser = $browser = Selenium::WebDriver.for :firefox, :profile => profile
browser.manage().window().maximize();
browser.get "https://cameleon-6945--dev.cs11.cloudforce.com"
main_window = browser.window_handle
browser.find_element(name:"username").clear()
browser.find_element(name:"username").send_keys "abcd#vertex.com"
browser.find_element(name:"pw").send_keys "1234"
browser.find_element(name:"Login").click
browser.find_element(link_text:"Cameleon Quotes").click
wait = Selenium::WebDriver::Wait.new(:timeout => 45)
#Open Test Run 1 created quote
wait.until {browser.find_element(:css,"#bodyCell > div.bRelatedList > div.hotListElement > div > div.pbBody > table > tbody > tr.dataRow.even.first > th > a")}
browser.find_element(:css,"#bodyCell > div.bRelatedList > div.hotListElement > div > div.pbBody > table > tbody > tr.dataRow.even.first > th > a").click
wait.until {browser.find_element(:xpath,"/html/body/div[3]/div[3]/div[2]/div[3]/div[2]/div[2]/div[2]/form/div[3]/div/div[2]/div[2]/div/div/div/table")}
#browser.save_screenshot "Cart Overview - RegressionRun # "+Time.now.strftime('%Y-%m-%d %H%M%S')+".jpeg"
#wait.until {browser.find_element(:css,"body > div.mainPartBox > div.boxBody > div.main > div.processBar > div.backgroundProcessBarMiddle > a:nth-child(7) > div.processBarElement.noSelected > div")}
#browser.find_element(:css,"body > div.mainPartBox > div.boxBody > div.main > div.processBar > div.backgroundProcessBarMiddle > a:nth-child(7) > div.processBarElement.noSelected > div").click
#wait.until {browser.find_element(:css,"body > div.CombinedBox > div.boxBody > div.main > div:nth-child(8) > iframe")}
#wait.until {browser.find_element(:xpath,"/html/body/div[3]/div[3]/div[2]/div[3]/iframe")}
browser.manage.timeouts.page_load = 35
#browser.switch_to.frame(cart_frame)
puts "\n\n"
puts "Assertions to verify cart content values\n\n".yellow
element_value1 = browser.find_element(:css,"#total > tbody > tr > td:nth-child(4) > span").text
if element_value1 == "$314,507.30"
puts 'Contract Sales Price = ' +element_value1
puts 'Value as expected in the cart, Test Passed'
else
puts 'Test failed, Contract Sales price value does not match the expected value'
end
puts "\n"
element_value2 = browser.find_element(:css,"#total > tbody > tr > td:nth-child(6) > span").text
if element_value2 == "$157,253.65"
puts 'Contract Cost Price = ' +element_value2
puts 'Value as expected in the cart, Test Passed'
else
puts 'Test failed, Contract Cost price value does not match the expected value'.red
end
puts "\n"
element_value3 = browser.find_element(:css,"#total > tbody > tr > td:nth-child(8) > span").text
if element_value3 == "50.00"
puts 'Contract gross margin = ' +element_value3
puts 'Value as expected in the cart, Test Passed'
else
puts 'Test failed, Gross margin value does not match the expected value'
end
puts "\n\n\t\t\t\t\tTest Case 1 passed successfully, proceeding to Test Case 2 - Generate Document\n".green
It's not integrated with any framework, it's just a test script.
My questions are:
Is this test totally worthless if compared to tools like Cucumber/Capybara etc.?
I have captured most of the elements using XPaths and this way the only way since it lacked classes, ids etc. Now if there's a minor change in page structure, like a new div is introduced, this script will fail with NoElemenFoundError. Is there any way we can avoid it? Or this is the only way test scripts are written and we need to update them regularly with new developments?
That exercise is worth doing once for your own experience. A couple of ways that using rspec for example would be an improvement are that rspec gives you a way to organize multiple tests, and that it boils down the results of your tests to a single indicator of success or failure, so that you can just look at the last line of output (or have your CI server look at the exit status) instead of reading pages of messages to see whether all your tests passed. Cucumber differs from rspec in that it allows you to read your entire test in English without reading any code in between, which is extremely valuable for thinking through requirements and might allow you to collaborate on your tests with non-programmers. Capybara provides methods that do much what you're doing in your script but are more succinct.
Sensitivity to page structure is an issue even with more sophisticated tools. One way to minimize the issue is to not assert any more of the page structure than you have to. If there is only one table on the page and only one row of results then td:nth-child(6) is all the selector you need. Another way to deal with that issue is to add IDs or classes to your pages to support testing.
I would say it is worth to have such scripts, but as soon as your number of scripts grows you need to manage them in a way where minimum maintenance is required.
So you can use various strategies to design a framework where you can have central object repository and test data. Refer here! for more details on designs.
I agree with Dave, to avoid assert on page structure. And if you maintain a central repository then there would be little modification needed if there is changes in structure of a page.

Parsing XML into CSV using Nokogiri

I am trying to figure out how to get Make and Model out of XML returned from a URL and put them into a CSV. Here is the XML returned from the URL:
<VINResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://basicvalues.pentondata.com/">
<Vehicles>
<Vehicle>
<ID>131497</ID>
<Product>TRUCK</Product>
<Year>1993</Year>
<Make>Freightliner</Make>
<Model>FLD12064T</Model>
<Description>120'' BBC Alum Air Cond Long Conv. (SBA) Tractor w/48'' Sleeper Air Brakes & Power Steering 6x4 (SBA - Set Back Axle)</Description>
</Vehicle>
<Vehicle>
<ID>131497</ID>
<Product>TRUCK</Product>
<Year>1993</Year>
<Make>Freightliner</Make>
<Model>FLD12064T</Model>
<Description>120'' BBC Alum Air Cond Long Conv. (SBA) Tractor w/48'' Sleeper Air Brakes & Power Steering 6x4 (SBA - Set Back Axle)</Description>
</Vehicle>
</Vehicles>
<Errors/>
<InvalidVINMsg/>
</VINResult>
Here is the code I have so far:
require 'csv'
require 'rubygems'
require 'nokogiri'
require 'open-uri'
vincarriercsv = 'vincarrier.csv'
vindetails = 'vindetails.csv'
vinurl = 'http://redacted/LookUp_VIN?key=redacted&vin='
CSV.open(vindetails, "wb") do |details|
CSV.foreach(vincarriercsv) do |row|
vinxml = Nokogiri::HTML(vinurl + row[1])
make = vinxml.xpath('//VINResult//Vehicles//Vehicle//Make').text
model = vinxml.xpath('//VINResult//Vehicles//Vehicle//Model').text
details << [ row[0], row[1], make, model ]
end
end
For some reason the URL returns the same data twice but I only need the first result. So far my attempts to grab the Make and Model from the XML has failed...any ideas?
Here's how to get at the make and model data. How to convert it to CSV is left to you:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<VINResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://basicvalues.pentondata.com/">
<Vehicles>
<Vehicle>
<ID>131497</ID>
<Product>TRUCK</Product>
<Year>1993</Year>
<Make>Freightliner</Make>
<Model>FLD12064T</Model>
<Description>120'' BBC Alum Air Cond Long Conv. (SBA) Tractor w/48'' Sleeper Air Brakes & Power Steering 6x4 (SBA - Set Back Axle)</Description>
</Vehicle>
<Vehicle>
<ID>131497</ID>
<Product>TRUCK</Product>
<Year>1993</Year>
<Make>Freightliner</Make>
<Model>FLD12064T</Model>
<Description>120'' BBC Alum Air Cond Long Conv. (SBA) Tractor w/48'' Sleeper Air Brakes & Power Steering 6x4 (SBA - Set Back Axle)</Description>
</Vehicle>
</Vehicles>
<Errors/>
<InvalidVINMsg/>
</VINResult>
EOT
vehicle_make_and_models = doc.search('Vehicle').map{ |vehicle|
[
'make', vehicle.at('Make').content,
'model', vehicle.at('Model').content
]
}
This results in:
vehicle_make_and_models # => [["make", "Freightliner", "model", "FLD12064T"], ["make", "Freightliner", "model", "FLD12064T"]]
If you don't want the field names:
vehicle_make_and_models = doc.search('Vehicle').map{ |vehicle|
[
vehicle.at('Make').content,
vehicle.at('Model').content
]
}
vehicle_make_and_models # => [["Freightliner", "FLD12064T"], ["Freightliner", "FLD12064T"]]
Note: You have XML, not HTML. Don't assume that Nokogiri treats them the same, or that the difference is insignificant. Nokogiri parses XML strictly, since XML is a strict standard.
I use CSS selectors unless I absolutely have to use XPath. CSS results in a much clearer selector most of the time, which results in easier to read code.
vinxml.xpath('//VINResult//Vehicles//Vehicle//Make').text doesn't work, because // means "start at the top of the document". Each time it's encountered Nokogiri starts at the top, searches down, and finds all matching nodes. xpath returns all matching nodes as a NodeSet, not just a particular Node, and text will return the text of all Nodes in the NodeSet, resulting in a concatenated string of the text, which is probably not what you want.
I prefer to use search instead of xpath or css. It returns a NodeSet like the other two, but it also lets us use either CSS or XPath selectors. If your particular selector was ambiguous and could be interpreted as either CSS or XPath, then you can use the explicit form. Likewise, you can use at or xpath_at or css_at to find just the first matching node, which is equivalent to search('foo').first.
You could also do the following which will place all of the vehicles in an Array and all of the vehicle attributes into a Hash
require 'nokogiri'
doc = Nokogiri::XML(open(YOUR_XML_FILE))
vehicles = doc.search("Vehicle").map do |vehicle|
Hash[
vehicle.children.map do |child|
[child.name, child.text] unless child.text.chomp.strip == ""
end.compact
]
end
#=>[{"ID"=>"131497", "Product"=>"TRUCK", "Year"=>"1993", "Make"=>"Freightliner", "Model"=>"FLD12064T", "Description"=>"120'' BBC Alum Air Cond Long Conv. (SBA) Tractor w/48'' Sleeper Air Brakes Power Steering 6x4 (SBA - Set Back Axle)"}, {"ID"=>"131497", "Product"=>"TRUCK", "Year"=>"1993", "Make"=>"Freightliner", "Model"=>"FLD12064T", "Description"=>"120'' BBC Alum Air Cond Long Conv. (SBA) Tractor w/48'' Sleeper Air Brakes Power Steering 6x4 (SBA - Set Back Axle)"}]
Then you can access all the attributes for an individual vehicle i.e.
vehicles.first["ID"]
#=> "131497"
vehicles.first["Year"]
#=> "1993"
etc.

Ruby - URL to Markdown

TOTAL rookie here.
I'm working on customizing a script made by Brett Terpstra - http://brettterpstra.com/2013/11/01/save-pocket-favorites-to-nvalt-with-ifttt-and-hazel/
Mine is a different use: I'd like to save my pinboard bookmarks with a specific tag to a file in dropbox in Markdown.
I feed it a text file such as:
Title: Yesterday is over.
URL: http://www.jonacuff.com/blog/want-to-change-the-world-get-doing/
Tags: 2md, 2wcx, 2pdf
Date: June 20, 2013 at 06:20PM
Image: notused
Excerpt: You can't start the next chapter of your life if you keep re-reading the last one.
And it outputs the markdown file.
Everything works great except when the 'excerpt' (see above) is more than one line. Sometimes it's a couple of paragraphs. When that happens, it stops working. When I hit enter from the command line, it's still waiting for more input.
Here's an example of a file that it doesn't work on:
Title: Talking ’bout my Generation.
URL: http://blog.greglaurie.com/?p=8881
Tags: 2md, 2wcx, 2pdf
Date: June 28, 2013 at 09:46PM
Image: notused
Excerpt: Contrast two men from the 19th century: Max Jukes and Jonathan Edwards.
Max Jukes lived in New York. He did not believe in Christ or in raising his children in the way of the Lord. He refused to take his children to church, even when they asked to go. Of his 1,026 descendants:
•300 were sent to prison for an average term of 13 years
•190 were prostitutes
•680 were admitted alcoholics
His family, thus far, has cost the state in excess of $420,000 and has made no contribution to society.
Jonathan Edwards also lived in New York, at the same time as Jukes. He was known to have studied 13 hours a day and, in spite of his busy schedule of writing, teaching, and pastoring, he made it a habit to come home and spend an hour each day with his children. He also saw to it that his children were in church every Sunday. Of his 929 descendants:
•430 were ministers
•86 became university professors
•13 became university presidents
•75 authored good books
•7 were elected to the United States Congress
•1 was Vice President of the United States
Edwards’ family never cost the state one cent.
We tend to think that our decisions only affect ourselves, but they have ramifications for generations to come.
Here's a screenshot of what it looks like after I run the command: https://www.dropbox.com/s/i9zg483k7nkdp6f/Screenshot%202013-11-22%2016.39.17.png
I'm hoping it's something easy. Any ideas?
#!/usr/bin/env ruby
# Works with IFTTT recipe https://ifttt.com/recipes/125999
#
# Set Hazel to watch the folder you specify in the recipe.
# Make sure nvALT is set to store its notes as individual files.
# Edit the $target_folder variable below to point to your nvALT
# ntoes folder.
require 'date'
require 'open-uri'
require 'net/http'
require 'fileutils'
require 'cgi'
$target_folder = "~/Dropbox/messx/urls2md"
def url_to_markdown(url)
res = Net::HTTP.post_form(URI.parse("http://heckyesmarkdown.com/go/"),{'u'=>url,'read'=>'1'})
if res.code.to_i == 200
res.body
else
false
end
end
file = ARGV[0]
begin
input = IO.read(file).force_encoding('utf-8')
headers = {}
input.each_line {|line|
key, value = line.split(/: /)
headers[key] = value.strip || ""
}
outfile = File.join(File.expand_path($target_folder), headers['Title'].gsub(/["!*?'|]/,'') + ".txt")
date = Time.now.strftime("%Y-%m-%d %H:%M")
date_added = Date.parse(headers['Date']).strftime("%Y-%m-%d %H:%M")
content = "Title: #{headers['Title']}\nDate: #{date}\nDate Added: #{date_added}\nSource: #{headers['URL']}\n"
tags = false
if headers['Tags'].length > 0
tag_arr = header s['Tags'].split(", ")
tag_arr.map! {|tag|
%Q{"#{tag.strip}"}
}
tags = tag_arr.join(" ")
content += "Keywords: #{tags}\n"
end
markdown = url_to_markdown(headers['URL']).force_encoding('utf-8')
if markdown
content += headers['Image'].length > 0 ? "\n\n> #{headers['Excerpt']}\n\n---#{markdown}\n" : "\n\n"+markdown
else
content += headers['Image'].length > 0 ? "\n\n![](#{headers['Image']})\n\n#{headers['Excerpt']}\n" : "\n\n"+headers['Excerpt']
end
File.open(outfile,'w') {|f|
f.puts content
}
if tags && File.exists?("/usr/local/bin/openmeta")
%x{/usr/local/bin/openmeta -a #{tags} -p "#{outfile}"}
end
# FileUtils.rm(file)
rescue Exception => e
puts e
end
How about this? Modify your input.each_line area accordingly:
headers = {}
key = nil
input.each_line do |line|
match = /^(?<key>\w+)\s*:\s*(?<value>.*)/.match(line)
value = line
if match
key = match[:key].strip
headers[key] = match[:value].strip
else
headers[key] += line
end
end
First, splitting on just ":" is dangerous since that can be in content. Instead, a (simplified from code) regex of /^\w+:.*/ will match "Word: Content". Since the lines after the "Excerpt:" aren't prefixed, you need to hang on to the last seen key, and just append if there's no key for this line. You may need to add a newline in there, depending on what you're doing with that header information, but it seems to work.

Smarty if statement with date?

If I have a smarty variable
{$test.date_created}
that displays a date in a smarty template, for example:
02/2/2012
On the smarty website, it says that you can display today's date with the following.
{$smarty.now|date_format:'%m/%d/%Y'}
How can I use it in an if statement to display a message when its 3 days old or more from today's date?
If its 3 days old or more, display "Old". If not, Display "New".
You can use strtotime() to get the timestamp corresponding to three days ago, and then compare this to the date of your message. For example, assuming $message is your message record and $message['date'] is the timestamp you have to check:
$isMessageOld = ($message['date'] <= strtotime('-3 days'));
$smarty->assign('isMessageOld', $isMessageOld);
And then, in your template:
{if $isMessageOld} ... {/if}
I'm not 100% sure, but you can also test it directly in Smarty. Assuming you have $message passed to Smarty:
{if $message.date <= strtotime('-3 days')} ... {/if}
You can easily check already passed date in smarty by using this $smarty.now
$smarty.now|date_format:"%Y%m%d"
Here is an example of cross the old(passed) date
<{foreach from=$meetings item=m}>
<{if $smarty.now|date_format:"%Y%m%d" <= $m.date|date_format:"%Y%m%d"}>
<tr>
<td><{counter}></td>
<td><{$m.title}> on </td>
<td><{$m.date}></td>
</tr>
<{else}>
<tr>
<td><strike><{counter}></strike></td>
<td><strike><{$m.title}> on </strike></td>
<td><strike><{$m.date}></strike></td>
</tr>
<{/if}>
<{/foreach}>
We need to create meeting list array in php and assign it in smarty
$meetings[0]['title'] = "Speech on Gandhi Janyanti";
$meetings[0]['date'] = "2-Oct-2011";
$meetings[1]['title'] = "Meet friend";
$meetings[1]['date'] = "10-Oct-2013";
$meetings[2]['title'] = "Goto USA";
$meetings[2]['date'] = "22-Oct-2013";
$meetings[3]['title'] = "Speech on Gandhi Janyanti";
$meetings[3]['date'] = "2-Oct-2014";
$meetings[4]['title'] = "Meeting with John";
$meetings[4]['date'] = "22-Oct-2014";
$meetings[5]['title'] = "Speech on Gandhi Janyanti";
$meetings[5]['date'] = "2-Oct-2015";
$meetings[6]['title'] = "Meeting with Uncle";
$meetings[6]['date'] = "22-Oct-2015";
$theme->assign("meetings",$meetings);
echo $theme->fetch("index.tpl");

Resources