Monday, February 28, 2011

The WWW constant is deprecated mechanize


!!!!! DEPRECATION NOTICE !!!!!
The WWW constant is deprecated, please switch to the new top-level Mechanize
constant.  WWW will be removed in Mechanize version 2.0

You've referenced the WWW constant from usa:57, please
switch the "WWW" to "Mechanize".  Thanks!

Sincerely,

  Pew Pew Pew






If you've updated to the latest version of Mechanize, there is no longer a need for the WWW.
From now on, you just do
browser = Mechanize.new

Mechanize::UnsupportedSchemeError

This happens when you are parsing javascript using Mechanize. Mechanize can't parse JavaScript. Look into using Harmony. harmony is here "https://github.com/mynyml/harmony"

Wednesday, February 23, 2011

How to find a date ago a particular date


     require 'chronic'
     Chronic.parse('1 year ago')
=> Tue Feb 23 18:08:36 +0530 2010
>> Chronic.parse('1 day ago')
=> Tue Feb 22 18:08:46 +0530 2011
>> Chronic.parse('5 day ago')
=> Fri Feb 18 18:08:51 +0530 2011
>> Chronic.parse('23 day ago')
=> Mon Jan 31 18:09:01 +0530 2011
>> Chronic.parse('1 month ago')
=> Sun Jan 23 18:09:13 +0530 2011


Chronic date/time parser


Chronic is a natural language date/time parser written in pure Ruby. See below for the wide variety of formats Chronic will parse.

INSTALLATION

The best way to install Chronic is with RubyGems:
$ [sudo] gem install chronic

USAGE

You can parse strings containing a natural language date using the Chronic.parse method.
require 'rubygems'
require 'chronic'

Time.now #=> Sun Aug 27 23:18:25 PDT 2006

#---

Chronic.parse('tomorrow')
#=> Mon Aug 28 12:00:00 PDT 2006

Chronic.parse('monday', :context => :past)
#=> Mon Aug 21 12:00:00 PDT 2006

Chronic.parse('this tuesday 5:00')
#=> Tue Aug 29 17:00:00 PDT 2006

Chronic.parse('this tuesday 5:00', :ambiguous_time_range => :none)
#=> Tue Aug 29 05:00:00 PDT 2006

Chronic.parse('may 27th', :now => Time.local(2000, 1, 1))
#=> Sat May 27 12:00:00 PDT 2000

Chronic.parse('may 27th', :guess => false)
#=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
See Chronic.parse for detailed usage instructions.

EXAMPLES

Chronic can parse a huge variety of date and time formats. Following is a small sample of strings that will be properly parsed. Parsing is case insensitive and will handle common abbreviations and misspellings.
Simple
  • thursday
  • november
  • summer
  • friday 13:00
  • mon 2:35
  • 4pm
  • 6 in the morning
  • friday 1pm
  • sat 7 in the evening
  • yesterday
  • today
  • tomorrow
  • this tuesday
  • next month
  • last winter
  • this morning
  • last night
  • this second
  • yesterday at 4:00
  • last friday at 20:00
  • last week tuesday
  • tomorrow at 6:45pm
  • afternoon yesterday
  • thursday last week
Complex
  • 3 years ago
  • 5 months before now
  • 7 hours ago
  • 7 days from now
  • 1 week hence
  • in 3 hours
  • 1 year ago tomorrow
  • 3 months ago saturday at 5:00 pm
  • 7 hours before tomorrow at noon
  • 3rd wednesday in november
  • 3rd month next year
  • 3rd thursday this september
  • 4th day last week
Specific Dates
  • January 5
  • dec 25
  • may 27th
  • October 2006
  • oct 06
  • jan 3 2010
  • february 14, 2004
  • 3 jan 2000
  • 17 april 85
  • 5/27/1979
  • 27/5/1979
  • 05/06
  • 1979-05-27
  • Friday
  • 5
  • 4:00
  • 17:00
  • 0800
Specific Times (many of the above with an added time)
  • January 5 at 7pm
  • 1979-05-27 05:00:00
  • etc

TIME ZONES

Chronic allows you to set which Time class to use when constructing times. By default, the built in Ruby time class creates times in your system's local time zone. You can set this to something like ActiveSupport's TimeZone class to get full time zone support.
>> Time.zone = "UTC"
>> Chronic.time_class = Time.zone
>> Chronic.parse("June 15 2006 at 5:45 AM")
=> Thu, 15 Jun 2006 05:45:00 UTC +00:00

Convert Epoch value to time/date ruby

To convert Epoch value to time/date you can do this

Time.at(Epoch value)
eg:

Time.at(946702800)    #=> 1999-12-31 23:00:00 -0600

Epoch date ruby


Current Time (from your computer)

Current Date/Time: (JavaScript)
1298467132 (Epoch)
Wed Feb 23 2011 18:48:52 GMT+0530 (IST) (Standard)
Current Date/Time: (PerlScript)
(Sorry, it doesn't appear that you have PerlScript installed.)

This section shows the output of two client-side scripting languages: JavaScript and PerlScript. Why JavaScript? (It's arguably the de facto standard for client-side scripting on the web.) Why PerlScript? (I just thought it was cool that there is a PERL interpreter for browsers, rare though it is.) I've left out VBScript, ...sorry. How the output for this section is generated is really secondary to the core date-to-epoch and epoch-to-date conversion topic. It's relevance in this example is that DHTML techniques using a client-side scripting language is what updates this webpage with your input without a reload from the server.


What is Epoch

Epoch has a few meanings (see also http://dictionary.reference.com/search?q=epoch). The definition that we'll use is "0" in computer time. While there are folks who will argue this, for our purposes, this "0" time on our calendar was January 1, 1970 00:00:00 GMT. Epoch is useful in the programming world because it allows us to mathematically compare dates with other dates or some other measure of time. Said another way, it allows us to use a programming algorithm to make decisions regarding a human readable date or time. See the examples of usage section below for more detail.


How to Convert between Date and Epoch

I've had a number of inquiries into how to do the conversion. I figured folks interested in that level of detail would use the source code for this page to ascertain the approach used here. However, I suppose assuming everyone enjoys deciphering the idiosyncrasies of JavaScript for fun was a bit naive... my bad. I'll take a stab at explaining what the code does.First off, the easiest way to get the current time in epoch (using JavaScript), is to call getTime() method of the JavaScript Date object and divide the return value by 1000. getTime returns the number of milliseconds elapsed, in your computer's timezone, since 1/1/1970 GMT. Because epoch is measured in seconds, you then want to divide the return value by 1000 to change milliseconds into seconds. Keep in mind that the JavaScript Date object will get it's time from your computer's clock. Here's a really simple example doing this.


<script type="text/javascript"><!-- function epochExample1(){ var d = new Date(); prompt('Cut/Paste into the converter to Test',(d.getTime()-d.getMilliseconds())/1000) } //--></script> <a href="#" onclick="epochExample1(); return false;">Click to Show Current Epoch Time</a>
Note: We're subtracting the milliseconds in order to get a whole number instead of a fraction. You could probably use parseInt similarly, in fact, here's another mini-example demonstrating the differences between (a) getTime()/1000 alone -- sometimes a fraction is returned, (b) method above, (getTime - milliseconds)/1000, and (c) parseInt(getTime/1000).

<script type="text/javascript"><!-- function testMethods1(){ /* testing differences between getTime/1000 vs. subtracting milliseconds vs. parseInt(getTime/1000) */ var d1 = new Date(); var d1t0 = d1.getTime()/1000; var d1t1 = (d1.getTime()-d1.getMilliseconds())/1000; var d1t2 = parseInt(d1.getTime()/1000); var msg = 'Testing various methods:' +'\n1) Date.getTime()/1000 = '+d1t0 +'\n2) (Date.getTime()-Date.getMilliseconds())/1000 = '+d1t1 +'\n3) parseInt(Date.getTime()/1000) = '+d1t2 alert(msg) return false } //--></script> <p><a href="#" onclick="return testMethods1()">Click to test</a> </p>
However, if you have a human friendly date/time that you want to convert. You can do what this tool does (though it kind of defeats the purpose of having a tool). You need to consider that the computer (like a calculator) is really good at not making a mistake. We'd have to unravel the Date Object's methods to accurately replicate what they are doing. That goes a little beyond the scope of this tool. :-) (Sorry, call me lazy.)
You could do a rough calculation as follows:
  1. Say its the year 2006. Determining the offset from "0" time in 1970 could be done as follows. 2006 - 1970 = 36 years. However, we haven't accounted for leap years. As I understand it, "the Gregorian calendar adds a 29th day to February 97 years out of 400." (source: http://www.answerbag.com/q_view/530626) If you want to walk through each year in the range and determine whether it's a leap year then have at it (wow, a tool would sure be nice ;-) ). For my purposes I'm going to say ...a leap year occurs approximately every four years. So, 36 / 4 means we'd have roughly 9 extra days during those 36 years. Converting the years to days we have 36 * 365 = 13140 days. And, adding in our "9" for approximate leap years 13140 + 9 = 13149 days.
  2. Now, let's say it's March 15 in that year. We need to calculate the day offset from January 1. January had 31 days, February had 28, and March has so far had 15. So we can add up our days, 31 + 28 + 15 = 74 days. Let's add this back into the days from the converted year. 13149 + 74 = 13223.
  3. Now let's convert our days into seconds (since epoch is seconds elapsed.) Each day has roughly 86,400 seconds in it. So 13223 * 86400 = 1142467200 seconds.
  4. Now we need the time offset since the start of the day. If we say it's 5:00 PM, then we convert 12 hour time into 24 hour time to get 17:00. That's 17 hours that have elapsed since 12:00:00. Each hour is 3600 seconds, so we can do the conversion as follows 17 * 3600 = 61200. Now add that back into the running total 1142467200 + 61200 = 1142528400.
  5. Note: If you have minutes and seconds, they'd need to be added in as well.
What we're left with is 1142528400 seconds since "0" time 1/1/1970. It's not very friendly from a human standpoint, but it's pure gold for computers and calculators in calculating "elapsed time since..." for a date that's been converted to epoch.Sanity checking your results
Plug 1142528400 back into the converter and see how far off March 15, 2006 you are. It's likely that you are off by some amount, probably the offset for your own local timezone. In general, you should always sanity check your results. Two good tests are, checking your results against today (using the current epoch from getTime/1000 for example), and "0" time. If your mechanism passes both tests, that's a good sign.
Another interesting note: I've heard folks suggest using UTC rather than local time. UTC is certainly an appropriate "global" approach to time based applications, particularly when your audience spans the globe; In that case, having a standard time to fallback on is excellent. In order to apply it to your specific locale, you would calculate the target timezone offset from UTC. There are some strange issues that come up. Calculating an offset accurately can be really tough in the real world. For example, Arizona time while correct in Windows, isn't correct in JavaScript. And that's just one example. I'm not an expert on timezones, so I don't know how prolific timezone offset problems are. I'd appreciate feedback from anyone in the know.


Examples of Usage

Of course, the most relevant question in all of this is "why would I want to do any of this?" I've had the need for this arise many times. One notable example which occurred while working for a web hosting company was that we wanted to turn messaging chunks on/off 3 days after a new signup for services. We had a marketing manager that wanted to play some messaging to our audience of webmasters three days into their experience. Because there is a steady inflow of customers, the exercise is an ongoing one, and relative to each specific account. We needed a way to identify a member of the 3+ day audience and then some logic to trigger the messaging. In turning that need into programming routines, we did the following steps.
  1. First, we stored the epoch value of the date of each signup (for example, Jan 1, 2003 is 1041459471 in epoch). Now that the date value is an integer, we can do math with it.
  2. Second, we calculate 3 days in epoch measures (seconds) as follows... (86400 * 3)
  3. Third, compare the current time with the signup time, plus the 3 days epoch value.
By making signup date a variable, this rule can apply to anyone for whom we want to know 3 days into the future of their signup.
ex: $signup_date = 1041459471 (or whatever the epoch is for any given site) if ($current_time > ($signup_date + (86400 * 3))) then this site was signed up more than 3 days ago.


Common Time Measures in Epoch

1 Millisecond = 1/1000 in Epoch (used frequently with JavaScript conversions)
1 Second = 1 in Epoch
1 Minute = 60 in Epoch
10 Minutes = 600 in Epoch
1 Hour = 3600 in Epoch
6 Hours = 21600 in Epoch
12 Hours = 43200 in Epoch
1 Day = 86400 in Epoch (24 Hours)
1 Week = 604800 in Epoch (7 Days / 168 Hours)
1 Month = (see below... number of days in the month)
 28 Days = 2419200 in Epoch (672 Hours)
 29 Days = 2505600 in Epoch (696 Hours)
 30 Days = 2592000 in Epoch (720 Hours)
 31 Days = 2678400 in Epoch (744 Hours)
 AVERAGE MONTHS IN YEAR = 2628000 in Epoch
  (365 / 12 = 30.416666666666666666666666666667) (average months)
  (30.416666666666666666666666666667 * 86400 = 2628000) (average months in Epoch)
1 Year = 31536000 in Epoch (365 days * 86400 seconds)


Source Code for Converter and Examples


<script type="text/javascript"><!-- /* Date/Epoch Functions Author: Thomas Ballard (http://thomas.ballard.ws) Copr. 2002-2008, E.S.Q. Software Note: slightly polluted to attempt to support a GMT/non-GMT (local) timezone offset feature. Hack and slash resulted in a form input having a toggle state... but these functions need to know that form and input to access the property for evaluation. Need to come back and make these methods more agnostic. */ if(!window.dDate) window.dDate = new Date() window.getEpoch = function(){ var GMT = document.ivnForm.GMT.checked if(GMT){ return parseInt(Date.UTC(dDate.getUTCFullYear(),dDate.getUTCMonth(),dDate.getUTCDate(),dDate.getUTCHours(),dDate.getUTCMinutes(),dDate.getUTCSeconds(),dDate.getUTCMilliseconds())/1000) } else { return (dDate.getTime()-dDate.getMilliseconds())/1000 } } window.getDays = function(mObj,dObj,yObj){ // build array of days in a select container based on selected month and year iMonth=parseInt(mObj.options[mObj.selectedIndex].value)+1 iYear=(yObj.value?yObj.value:1900); var iDays=31; switch(iMonth){ /* determine the number of days this month including leap years */ case 4: case 6: case 9: case 11: --iDays; break; case 2: iDays=29; if (((iYear%4)!=0) || ((iYear%100)==0)) --iDays; } dObj.options.length = 0; for(var i=0; i<iDays; i++){ dObj.options[i] = new Option(i+1,i+1) } } window.toDate = function(eObj){ var mEpoch = parseInt(eObj.value); if(mEpoch<10000000000) mEpoch *= 1000; // convert to milliseconds (Epoch is usually expressed in seconds, but Javascript uses Milliseconds) dDate.setTime(mEpoch) zObj.innerHTML = dDate } window.toEpoch = function(mObj,dObj,yObj,hrObj,minObj,secObj){ var month = mObj.options[mObj.selectedIndex].value var day = dObj.options[dObj.selectedIndex].value var year = yObj.value var hour = hrObj.options[hrObj.selectedIndex].value var minute = minObj.options[minObj.selectedIndex].value var second = secObj.options[secObj.selectedIndex].value //alert(month+']+day+['+year) dDate.setMonth(month,day) dDate.setFullYear(year) dDate.setHours(hour,minute,second) //alert(dDate) zObj.innerHTML = window.getEpoch() if(window && window.clipboardData && window.clipboardData.setData) bResult = window.clipboardData.setData("Text",zObj.innerHTML); //stuff the text onto the clipboard } //--></script> <script type="text/javascript"><!-- var zObj = document.getElementById('dynamo') var fobj = document.forms.ivnForm if(fobj.GMT.checked){ // GMT TIME var dDate = new Date(Date.UTC(dDate.getUTCFullYear(),dDate.getUTCMonth(),dDate.getUTCDate(),dDate.getUTCHours(),dDate.getUTCMinutes(),dDate.getUTCSeconds(),dDate.getUTCMilliseconds())); fobj.month.selectedIndex = dDate.getUTCMonth(); // set initial month to current fobj.year.value = dDate.getUTCFullYear() getDays(fobj.month,fobj.day,fobj.year) fobj.day.selectedIndex = dDate.getUTCDate()-1 fobj.epoch.value = window.getEpoch() fobj.hour.selectedIndex = dDate.getUTCHours(); fobj.minute.selectedIndex = dDate.getUTCMinutes(); fobj.second.selectedIndex = dDate.getUTCSeconds(); } else { // LOCAL TIME var dDate = new Date(); fobj.month.selectedIndex = dDate.getMonth(); // set initial month to current fobj.year.value = dDate.getFullYear() getDays(fobj.month,fobj.day,fobj.year) fobj.day.selectedIndex = dDate.getDate()-1 fobj.epoch.value = window.getEpoch() fobj.hour.selectedIndex = dDate.getHours(); fobj.minute.selectedIndex = dDate.getMinutes(); fobj.second.selectedIndex = dDate.getSeconds(); } //window.dDate = new Date(); var GMT = document.ivnForm.GMT.checked if(GMT){ var html = parseInt(Date.UTC(dDate.getUTCFullYear(),dDate.getUTCMonth(),dDate.getUTCDate(),dDate.getUTCHours(),dDate.getUTCMinutes(),dDate.getUTCSeconds(),dDate.getUTCMilliseconds())/1000)+' (Epoch)' + '<br>'+dDate.toUTCString()+' (Standard)' } else { var html = (dDate.getTime()-dDate.getMilliseconds())/1000+' (Epoch)' + '<br>'+dDate+' (Standard)' } if(document && document.getElementById){ obj = document.getElementById('jdate1') if(obj) obj.innerHTML = html } //--></script> <script type="text/perlscript"> $obj = $window->document->getElementById('pdate1'); $obj->{innerHTML} = time . " (Epoch)<br>" . localtime(time) . " (Standard)"; </script>

Monday, February 21, 2011

Open the default browser in Ruby


Cross-platform solution
First, install the Launchy gem:
$ [sudo] gem install launchy
Then, you can run this:
require 'rubygems'
require
'launchy'
Launchy.open("http://www.example.com")

Illegal characters in url

You may get bad uri error if your urls have illegal character. What you have to do is to replace then with their equalant legal character, see the link below


http://www.blooberry.com/indexdot/html/topics/urlencoding.htm

Embedding and extracting primary key in a clean URL

Clean URLs are very important for search engines and for that reason I always prefer them.

A url of the form http://rubyonrails.blogspot.com/article/55 is better than http://rubyonrails.blogspot.com/?aid=55.

An even better form of the URL is http://rubyonrails.blogspot.com/article-title-55 where article-title represents the important keywords that appear in the title.

When using Ruby on Rails, you can create the permalink from title using the following function:

def create_permalink(string)
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
'%' + $1.unpack('H2' * $1.size).join('%').upcase
end.tr(' ', '-').downcase

end

and you can extract the id from this permalink using a function given below:
def get_id_from_permalink(permalink)
@temp_array = permalink.split('-')
id=@temp_array[-1]
return id
end

Make a remote URL work like a file upload (in Rails)

Want to load a remote URL into an acts_as_attachment/attachment_fu model? Use this little utility class.

class UrlUpload
EXTENSIONS = {
"image/jpeg" => ["jpg", "jpeg", "jpe"],
"image/gif" => ["gif"],
"image/png" => ["png"]
}
attr_reader :original_filename, :attachment_data
def initialize(url)
@attachment_data = open(url)
@original_filename = determine_filename
end

# Pass things like size, content_type, path on to the downloaded file
def method_missing(symbol, *args)
if self.attachment_data.respond_to? symbol
self.attachment_data.send symbol, *args
else
super
end
end

private
def determine_filename
# Grab the path - even though it could be a script and not an actual file
path = self.attachment_data.base_uri.path
# Get the filename from the path, make it lowercase to handle those
# crazy Win32 servers with all-caps extensions
filename = File.basename(path).downcase
# If the file extension doesn't match the content type, add it to the end, changing any existing .'s to _
filename = [filename.gsub(/\./, "_"), EXTENSIONS[self.content_type].first].join(".") unless EXTENSIONS[self.content_type].any? {|ext| filename.ends_with?("." + ext) }
# Return the result
filename
end
end


Now when you have the URL you want to load, do something like this:

@model.uploaded_data = UrlUpload.new(url)


Or better yet, make a pseudo-accessor on your aaa/attachment_fu model so you can stay "model-heavy".

def url=(value)
self.uploaded_data = UrlUpload.new(value)
end

Sunday, February 20, 2011

How to rename a Rails 3 Application


Renaming a Rails 3 application is something you have to think about now. No, really… :)
When you create a new Rails 3.0 app with “rails app_name” Rails will create the application for you like before, but with a major difference.
It will Classify your “app_name” and use this as the Ruby name space for your application.
So if you do:
rails new app_name
Then your Rails application will have sprinklings of AppName throughout the tree.
If you later decide that your application should be called something more specific than “AppName” you need to replace out AppName from the following files:
config/application.rb
config/environment.rb
config/environments/development.rb
config/environments/test.rb
config/environments/production.rb
config/routes.rb
config.ru
initializers/secret_token.rb
initializers/session_store.rb
Of course, if you are using TextMate, a simple Project wide search and replace for AppName with your new name, should do the trick. But it is something to be aware of.

Rails 3 validations

Where did the scripts go?


The recent commit removing the contents of the script directory streamlines rails somewhat. But there were a lot of files in that directory, this is a quick cheat sheet on what replaces what…
The script directory used to contain
Old Script FileHow to use nowShortcut Command
aboutrake about
serverrails serverrails s
consolerails consolerails c
dbconsolerails dbconsolerails db
generaterails generaterails g
destroyrails destroy
performance/benchmarkrails benchmark
performance/profilerrails profiler
pluginrails plugin
runnerrails runner
As you can see from the above, the serverconsoledbconsole andgenerate parameters also have shortcut aliases.
When you run the rails command from within a Rails application directory, the above commands work, however, if you run the railscommand from outside a Rails application directory, then the usual Rails initialization command works in the format of rails/railties/bin/rails APP_PATH [options]
Note with the new 3.0 rails command, the APP_NAME has been changed to an APP_PATH and any options now come at the end, not before. APP_PATHallows you to initialise a new Rails application at some other path name and uses the last part of the path name for your application.
One word of warning, if you are running the Rails 3.0 Beta using the —devflag from a clone of the Rails source tree, then be sure to callscript/rails otherwise the rails binary that is run will be from your system gems, and you will end up initialising a new Rails application inside your new Rails 3 app directory.