Ruby Basics, Web & SQL Basics

The Beginning of the Ruby Road

So, I’m wondering how to gracefully lead you into the wonderful world of Ruby. Lots of folks have done it (eg. _why the lucky stiff, Chris Pine) and I definitely think you should check out their efforts. For now though, let’s learn by doing.

Getting Started

First stop: Get Ruby.

Windows: This is a great getting started walkthrough for windows folks. That covers a full setup of Rails, Ruby Subversion and MySQL. For now all you need is Ruby, which is easy with the One-click Installer

OSX: It’s builtin, but it would be good to get the latest ruby and rubygems too

Linux: Grab Ruby 1.8.4 through your favorite package manager or by source

Done? Great. Let’s hit up irb.

Everything is an Object

Open up a terminal and let’s kick things off.

$ irb --simple-prompt >> puts "hello" => "hello"

Wow. That’s like 0 to “Hello World” in 0.000574 secs. That’s not impressive though. What is impressive is that little string is an object packed with attributes and methods. In fact, in Ruby everything is an object and are ready to try just about whatever you can think to throw at them. We can call "hello".methods to get an array of all the methods available to “hello”. There’s over 150. That’s pretty cool.

Some of these methods show off some of good Ruby conventions, such as methods ending with a exclamation point (!) are dangerous methods and usually involve destructive actions to your object. For example my_string.reverse! will reverse my_string whereas my_string.reverse will return a copy of my_string reversed without altering the object. Here’s a quick list for string:

>> "hello".methods.grep(/\!/) => ["sub!", "upcase!", "delete!", "lstrip!", "succ!", "gsub!", "squeeze!", "downcase!", "rstrip!", "slice!", "chop!", "capitalize!", "tr!", "chomp!", "next!", "swapcase!", "reverse!", "tr_s!", "strip!"]

Another convention is to end methods with a question mark (?) for methods that return true or false. For example my_string.empty? will return true on the empty string. Here’s a quick list of those:

>> "hello".methods.grep(/\?/) => ["respond_to?", "eql?", "is_a?", "between?", "tainted?", "member?", "all?", "empty?", "any?", "nil?", "include?", "instance_of?", "equal?", "frozen?", "kind_of?"]

Oh, methods ending with an equals (=) are for definitions and setting values.

Methods call work like sending messages. The receiver (the object you’re calling the method on) takes the message and tries to find the appropriate response. This allows us to string them along merrily, like in the above snippets "hello".methods.grep(/\?/). If you try to called a method that isn’t defined, you’ll get a NoMethodError but Ruby thinks about it first. There’s a way to sneak in extra functionality here. Using method_missing, you can catch these leftover methods and try to work something out. This is really powerful and branches out into one of Ruby’s great gems, metaprogramming. Rails uses this a lot. That’s more advanced than we need right now, but leave it in the back of your mind for when the question comes up as to just how Rails can work such magic.

Let’s Get this Party Started

To start off with, we’ll get more acquainted with some of the built-in objects in Ruby while exploring some web and SQL concepts that we will be needing. Everyone should spend some time on there own exploring the various types (for our purposes the most useful will probably be Arrays, Hashes and Regular Expressions—yes even regular expressions are full objects in Ruby).

Arrays are fun in Ruby. There are many ways to create and access arrays in Ruby. Here’s a quick look:

>> array = ['one', 'two', 3] => ["one", "two", 3] >> array.first => "one" >> array.last => 3 >> array[0] => "one"

There’s also several ways to add items to an array.

>> array << 'four' # this will add 'four' to the end of the array => ["one", "two", 3, "four"] >> array.push(5) # like a stack => ["one", "two", 3, "four", 5] >> array.length => 5

Perhaps the most interesting example involves using Blocks. Iterating over an array is such a common task, but what you do to each element can vary. Wouldn’t it be nice if you could look at each element and then simply specify the code you want to run on it. This is the idea behind Blocks.

>> array.each do |element| ?> puts element # this is the code we want to run on each element >> end one two 3 four 5 => ["one", "two", 3, "four", 5]

Up next, hashes. Hashes work in pairs, key => value (eg. { :name => 'dedi' }). Unlike arrays, hashes aren’t kept in any particular order. Rails uses hashes a lot to collect information like url paramaters and configuration options.

>> params = { 'query' => 'rails', 'numresults' => 5, 'lang' => 'english' } => {"numresults"=>5, "lang"=>"english", "query"=>"rails"} >> params.keys => ["numresults", "lang", "query"] >> params.values => [5, "english", "rails"] >> params.has_value? 'rails' => true

We’ll be exploring further in class and assigned readings. Make sure to document your first impressions, thoughts and first bits of Ruby in your Development Journal.

Part II: Deep in the Ruby Wood

But What About Databases? Give Me SQL

In order to follow along, you should install sqlite if you’re on windows (it comes with osx) and then sqlite3-ruby gem (or additionally the mysql gem). That’s as easy as:

$ gem install sqlite3-ruby (optional) $ gem install mysql -- --with-mysql-config=/path/to/mysql_config

(note that you’ll need administrative privileges for this, so you may have to use sudo).

The benefits of using SQLite for development are a fast (as fast or faster than MySQL), file based and simple database. You can move the database around since it’s just a file and security is based on file permissions. You can also run the database in memory. It’s great for websites that have a small audience as well (<100,000 hits/day), it suffers a bit with lots of concurrent writes.

Let’s get started.

$ sqlite3 mydb.db SQLite version 3.1.3 Enter ".help" for instructions sqlite>

The basic SQL that we will need comes in the following flavors, CREATE, DROP, INSERT, UPDATE, SELECT, DELETE. For some reason (probably readability—whatever) people tend to type SQL words in uppercase. It’s up to you but I’m sticking to lowercase. For a quick peek at the syntax of each, click on the links above, for now back to sqlite.

sqlite>create table posts( "id" integer primary key not null, "body" text, "date" date); sqlite>insert into posts(body,date) values("testing",current_date); sqlite>insert into posts(body,date) values("another test","2006-12-25"); sqlite>select * from posts; 1|testing|2006-05-14 2|another test|2006-12-25

So, basically we’ve create a database to collect posts, inserted two test posts and then grabbed them back again.

Exercises

Exercise-1-1
# Exercise:  Take this file and add some RSS parsing to it.
# Perhaps revealing which items are new since the last time you checked.

require 'open-uri'

url = 'http://scoops.totallyrule.com/xml/rss/feed.xml' # pick an rss feed to track
lastfile = 'lastmod.log' # file to save/retrieve the time we checked

# let's check to see when we last hit this feed
lastcheck = File.open(lastfile, 'r').read.chomp

# now convert the time to a Time object with the correct net standard
lastcheck = Time.parse(lastcheck).rfc2822

begin

  # we're passing in a simple hash to apply our header
  # If-Modified-Since will compare our time to the modified time of the file
  # on the server and if it's newer than lastcheck it will give us the feed
  # otherwise we get nothing and the rescue part kicks in

  open(url, { 'If-Modified-Since' => lastcheck }) do |feed|
    puts "The feed has changed.\n"

    # Try something more interesting here with the rss module
    # Tutorial: http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.en
  end

rescue OpenURI::HTTPError # the exception open-uri throws on http errors
  puts "No file available or file has not changed.\n"
ensure

  # save the time of this check
  # this part happens good or bad

  File.open(lastfile, 'w') do |f|
    f.write(Time.now.to_s + "\n")
  end
end

link download

Exercise-1-2
# Try out the flickr.rb library http://redgreenblu.com/flickr/
# Use it to find interesting photos based on users or tags
# store some of the information in a sqlite database

require 'rubygems'
require 'flickr' # insanely easy flickr library
require 'sqlite3'

# NOTE: create the sqlite3 database beforehand or do it in code.
db = SQLite3::Database.new('flickr.db')

flickr = Flickr.new
dedi = flickr.users('dedi')

criteria = { 'user_id' => dedi.id, 'tags' => 'itp', 'privacy_filter' => '1' }

for photo in flickr.photos(criteria)
  db.execute("sql statement")
end

link download

Homework (Due 2006-05-22)

Reading

Things to Try

Development Journal