Oct 08 2009

What’s your moniker

Categories: Computers, Programming
Tags: ,

IMG_6929We were playing with some ideas over at PostRank and realized we needed a way to give out some unique codes. We didn’t want some random string of letters and numbers as that isn’t very memorable. We wanted real words. We wanted something entertaining.

I spent a bit of time looking around. The closest thing I found to what we wanted was Webster. While Webster would work, I wasn’t a big fan of the words we were getting out of the system in some quick tests. After some more fruitless searching, in a fit of not invented here syndrome, I created my own.

Enter, Moniker. Moniker will take a list of descriptive words and a set of animals and give you a string. There are, currently, just over 42 thousand combinations. Enough for what we needed. The system is pretty simplistic and it’s up to you to make sure you aren’t getting duplicates.

titania:~ dj2$ irb
>> require ‘rubygems’
>> require ‘moniker’
=> true
>> Moniker.name
=> "octagon-zebra"
>> Moniker.name
=> "shallow-lion"
>> Moniker.name
=> "concave-parrot"

The code is all up on GitHub so take a look and feel free to play. Let me know if you’ve got any ideas for improvements

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Jul 15 2009

EventMachine Screencast — EM-HTTP-Request

IMG_6037I decided to try my hand at creating a screencast the other day. I took a look at the EventMachine EM-HTTP-Request library and created a simple shell program to do single and multi requests. Take a look and let me know what you think.

require ‘rubygems’
require ‘eventmachine’
require ‘em-http’
require ‘pp’

$stdout.sync = true

class KeyboardHandler < EM::Connection
  include EM::Protocols::LineText2
 
  def post_init
    print "> "
  end
 
  def receive_line(line)
    line.chomp!
    line.gsub!(/^\s+/, )
   
    case(line)
    when /^get (.*)$/ then
      site = $1.chomp
      sites = site.split(‘,’)
     
      multi = EM::MultiRequest.new
      sites.each do |s|
        multi.add(EM::HttpRequest.new(s).get)
      end
      multi.callback {
        puts ""
        multi.responses[:succeeded].each do |h|
          pp h.response_header.status
          pp h.response_header
        end
        multi.responses[:failed].each do |h|
          puts "#{h.inspect} failed"
        end
        print "> "
      }
      print "> "

    when /^exit$/ then
      EM.stop

    when /^help$/ then
      puts "get URL[,URL]*   – gets a URL"
      puts "exit      - exits the app"
      puts "help      - this help"
      print "> "
    end
  end
end

EM::run {
  EM.open_keyboard(KeyboardHandler)
}
puts "Finished"

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Jul 07 2009

Google Analytics, OAuth and Ruby. Oh, my.

Categories: Computers, Programming
Tags: , ,

IMG_6658I recently had the opportunity to take a peek at accessing Google Analytics data using their OAuth endpoint. We did this in Ruby using the Ruby OAuth gem. There were a few snags along the way so I figured I’d put up some notes for other people to take a peek.

First, you’re going to need a newer version of the OAuth gem (0.3.5 seems to work). Google uses some features from the 1.0a version of the OAuth spec, the oauth_verifier specifically, that aren’t available in older versions of the OAuth gem. That took a while to track down.

The second thing you’re going to need is a consumer token and secret from google. You can retrieve this from your domain management page (here as it’s a bit difficult to find.)

require ‘oauth’
con = OAuth::Consumer.new(CONSUMER_TOKEN, CONSUMER_SECRET,
                              {:site => ‘https://www.google.com’,
                               :request_token_path => ‘/accounts/OAuthGetRequestToken’,
                               :access_token_path => ‘/accounts/OAuthGetAccessToken’,
                               :authorize_path => ‘/accounts/OAuthAuthorizeToken’})

To start we create our OAuth connection. You’ll need to substitute your token and secret for the consumer constants above. We need to specify all of the OAuth paths to match the endpoints provided by Google.

rt = con.get_request_token({}, {:scope => ‘https://www.google.com/analytics/feeds’})

We use the connection to create a request token. get_request_token takes two parameters. The token parameters and other parameters. Above, I’m not specifying any request parameters but, if you want Google to redirect the user to a site of your choice you would provide {:oauth_callback => URL} as the token parameter. After authenticating the user would be redirected to the provided URL and the parameters oauth_token=TOKEN and oauth_verifier=VERIFIER will be passed to the URL. You’ll need to use those parameters when creating the access token.

The second parameter when creating the request token is used by Google to restrict the users access to specific portions of Google. In our case we’re requesting access to the Analytics data. A list of available scopes is here. You can specify multiple scope values by putting a space between them. e.g. "http://www.google.com/calendar/feeds/%20http://docs.google.com/feeds/".

rt.authorize_url       => "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=4%2F-1o2aZgHxJmjhaExv9htRsGWLlwy"

google-1With our request token in hand we can use it to generate the authorization URL. You’ll need to redirect the user to this URL to do the authentication.

Since we aren’t providing a callback URL our users will just get redirected to a standard Google page and you’ll need to copy their verifier code into the application.

at = rt.get_access_token(:oauth_verifier => ‘vQH9bpXateNpsISpEDZax’)

google-2When the user has authorized we either get them to paste the verifier code or we can retrieve it from the parameters passed to our oauth_callback. We use the verifier code to create an access token. This is the token we’ll be using to access the Google resources. We can save the at.token and at.secret values into our database to create new access tokens next time the user needs data from Google. We don’t need to authenticate each time.

at = OAuth::AccessToken.new(con, USER_TOKEN, USER_SECRET)

We can also, if we’re using the oauth_callback store some of our request token information to the session. If we store rt.token and rt.secret we can re-build our request token in a simlar fashion to the access token.

rt = OAuth::RequestToken.new(con, REQUEST_TOKEN, REQUEST_SECRET)

With the authentication out of the way we can get on with accessing the analytics data.

puts at.get("https://www.google.com/analytics/feeds/accounts/default?prettyprint=true").body

We grab our profile data first. You’ll need the dxp:tableId value in order to make calls to get profile specific analytic data. (The prettyprint=true is a handy little flag to get Google to nicely indent the XML returned. Makes for easier reading/debugging.)

< ?xml version=‘1.0′ encoding=‘UTF-8′?>
<feed xmlns=‘http://www.w3.org/2005/Atom’ xmlns:openSearch=‘http://a9.com/-/spec/opensearchrss/1.0/’ xmlns:dxp=‘http://schemas.google.com/analytics/2009′>
  <id>http://www.google.com/analytics/feeds/accounts/dan.sinclair@gmail.com</id>
  <updated>2009-07-06T11:00:09.000-07:00</updated>
  <title type=‘text’>Profile list for dan.sinclair@gmail.com</title>
  <link rel=’self’ type=‘application/atom+xml’ href=‘http://www.google.com/analytics/feeds/accounts/default’/>
  <author>
    <name>Google Analytics</name>
  </author>
  <generator version=‘1.0′>Google Analytics</generator>
  <opensearch :totalResults>1</opensearch>
  <opensearch :startIndex>1</opensearch>
  <opensearch :itemsPerPage>1</opensearch>
  <entry>
    <id>http://www.google.com/analytics/feeds/accounts/ga:123xxxx</id>
    <updated>2009-07-06T11:00:09.000-07:00</updated>
    <title type=‘text’>everburning</title>
    <link rel=‘alternate’ type=‘text/html’ href=‘http://www.google.com/analytics’/>
    <dxp :tableId>ga:123xxxx</dxp>
    <dxp :property name=‘ga:accountId’ value=‘73xxxx’/>
    <dxp :property name=‘ga:accountName’ value=‘everburning’/>
    <dxp :property name=‘ga:profileId’ value=‘123xxxx’/>
    <dxp :property name=‘ga:webPropertyId’ value=‘UA-73xxxx-1′/>
    <dxp :property name=‘ga:currency’ value=‘USD’/>
    <dxp :property name=‘ga:timezone’ value=‘America/Toronto’/>
  </entry>
</feed>

puts at.get("https://www.google.com/analytics/feeds/data?ids=ga:123xxxx&start-date=2009-06-05&end-date=2009-06-06&dimensions=ga:pagePath&metrics=ga:pageviews,ga:uniquePageviews&prettyprint=true").body

The data I want from Google Analytics is the number of ga:pageviews and ga:uniquePageviews for each ga:pagePath between June 5th and 6th.

< ?xml version=‘1.0′ encoding=‘UTF-8′?>
<feed xmlns=‘http://www.w3.org/2005/Atom’ xmlns:openSearch=‘http://a9.com/-/spec/opensearchrss/1.0/’ xmlns:dxp=‘http://schemas.google.com/analytics/2009′>
  <id>http://www.google.com/analytics/feeds/data?ids=ga:123xxxx&amp;dimensions=ga:pagePath&amp;metrics=ga:pageviews,ga:uniquePageviews&amp;start-date=2009-06-05&amp;end-date=2009-06-06</id>
  <updated>2009-06-06T16:59:59.999-07:00</updated>
  <title type=‘text’>Google Analytics Data for Profile 123xxxx</title>
  <link rel=’self’ type=‘application/atom+xml’ href=‘http://www.google.com/analytics/feeds/data?end-date=2009-06-06&amp;start-date=2009-06-05&amp;metrics=ga%3Apageviews%2Cga%3AuniquePageviews&amp;ids=ga%3A123xxxx&amp;dimensions=ga%3ApagePath’/>
  <author>
    <name>Google Analytics</name>
  </author>
  <generator version=‘1.0′>Google Analytics</generator>
  <opensearch :totalResults>52</opensearch>
  <opensearch :startIndex>1</opensearch>
  <opensearch :itemsPerPage>52</opensearch>
  <dxp :startDate>2009-06-05</dxp>
  <dxp :endDate>2009-06-06</dxp>
  <dxp :aggregates>
    <dxp :metric confidenceInterval=‘0.0′ name=‘ga:pageviews’ type=‘integer’ value=‘162′/>
    <dxp :metric confidenceInterval=‘0.0′ name=‘ga:uniquePageviews’ type=‘integer’ value=‘152′/>
  </dxp>
  <dxp :dataSource>
    </dxp><dxp :tableId>ga:1239xxxx</dxp>
    <dxp :tableName>everburning</dxp>
    <dxp :property name=‘ga:profileId’ value=‘123xxxx5′/>
    <dxp :property name=‘ga:webPropertyId’ value=‘UA-73xxxx-1′/>
    <dxp :property name=‘ga:accountName’ value=‘everburning’/>
 
  <entry>
    <id>http://www.google.com/analytics/feeds/data?ids=ga:123xxxx&amp;ga:pagePath=/&amp;start-date=2009-06-05&amp;end-date=2009-06-06</id>
    <updated>2009-06-05T17:00:00.001-07:00</updated>
    <title type=‘text’>ga:pagePath=/</title>
    <link rel=‘alternate’ type=‘text/html’ href=‘http://www.google.com/analytics’/>
    <dxp :dimension name=‘ga:pagePath’ value=‘/’/>
    <dxp :metric confidenceInterval=‘0.0′ name=‘ga:pageviews’ type=‘integer’ value=‘9′/>
    <dxp :metric confidenceInterval=‘0.0′ name=‘ga:uniquePageviews’ type=‘integer’ value=‘8′/>
  </entry>
  <entry>
    <id>http://www.google.com/analytics/feeds/data?ids=ga:123xxxx&amp;ga:pagePath=/quotes/&amp;start-date=2009-06-05&amp;end-date=2009-06-06</id>
    <updated>2009-06-05T17:00:00.001-07:00</updated>
    <title type=‘text’>ga:pagePath=/quotes/</title>
    <link rel=‘alternate’ type=‘text/html’ href=‘http://www.google.com/analytics’/>
    <dxp :dimension name=‘ga:pagePath’ value=‘/quotes/’/>
    <dxp :metric confidenceInterval=‘0.0′ name=‘ga:pageviews’ type=‘integer’ value=‘6′/>
    <dxp :metric confidenceInterval=‘0.0′ name=‘ga:uniquePageviews’ type=‘integer’ value=‘6′/>
  </entry>
</feed>

You may notice that all of the paths returned are relative to some base URL. I haven’t been able to figure out how to get Google Analytics to tell me what that base URL happens to be. If you figure it out, please leave a comment so I can update my code.

That’s it. You can take a deeper look at the Google Analytics API documentation to learn about the different dimensions and metrics that can be queried.

If you’re doing this in Ruby you may also want to take a look at the Happy Mapper gem to make your XML using life easier.

Have fun.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Feb 27 2009

EventMachine Introductions

3006675951_a6fab89429_oAs you may know, we use EventMachine a lot at work. I’ve had a bit more time to get familiar with EventMachine then some of the other guys here and was asked to do a presentation to get everyone on the same page.

Not knowing where to start, I started from, what I think is, the start. So, if you’re interested, you can check out the EventMachine Presentation or the EventMachine Introduction I wrote to support the presentation. (Note, it looks like Evince doesn’t draw the background correctly in the presentation so it might look a little strange but readable).

There is a lot more stuff I could add to the introduction, I’ve just run into time constraints at this point. Hopefully, I’ll be able to expand the introduction and get into some of the non-core EM software like EM-HTTP-Request and the EM AMQP library.

Let me know if you have any questions or comments.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Jan 15 2009

Playing with EventMachine

img_5305I’ve had a bit of opportunity to play with Ruby EventMachine over the last few weeks at work. While the RDoc is very helpful it’s still a bit of work to figure things out. To that end, I figured I might try to write some stuff down.

The first question is typically, what is this EventMachine thing and how come when I use it the rest of my application doesn’t execute. Well, simply put, EM (EventMachine) is an event loop. Once you kick off EventMachine it takes over the execution of your main Ruby thread and does its own thing. EM will listen on sockets, on file descriptors, set timers and various other procedures. When activity happens on the things EM is listening too it will trigger event callbacks to your code. You handle the event then return control to EventMachine.

It’s also possible to have EventMachine execute a block of long running code on another thread so you don’t hold up the entire run loop with your work. When the process is done a callback can be executed on the main thread to handle any responses to the original connection.

Hopefully this will all become more clear as we look at some code.

Timer Example


#!/usr/bin/ruby

require 'rubygems'
require 'eventmachine'

EventMachine.run do
    EM.add_periodic_timer(1) { puts "Tick ..." }

    EM.add_timer(3) do
        puts "I waited 3 seconds"
        EM.stop_event_loop
    end
end

puts "All done."

Nothing too complicated here. Let’s, as they say, start at the start. I’ve installed Eventmachine through rubygems (gem install eventmachine) so I need the proper requires to get everything available. You’ll notice I’m using both EventMachine and EM, they’re interchangeable. I prefer EM as it’s shorter but sometimes use EventMachine anyway. The call to EventMachine#run is what kicks off the main event loop. Before the event loop is started the block provided to EM#run will be executed. This is where you can setup your various servers, timers and other handlers as needed.

In this example I creating two timers. Using EM#add_timer I’ve created a timer that will execute once in at least three seconds. The EM#add_periodic_timer creates a timer that will execute every one second. In both cases when the event is fired it will execute the block attached to the timer creation call.

For the timer which fires each second we do a simple puts call. In the single shot timer we have a call to EM#stop_event_loop. EM#stop_event_loop will cause the EventMachine event loop to stop executing. Once the event loop is terminated the control flow of the application will pickup again after the EM#run block and execute the final puts statement.

So, as you can see, any code we have after the call to EM#run will not get executed until the event loop is shutdown. Typically when your application is terminating.

Server Example


#!/usr/bin/ruby

require 'rubygems'
require 'eventmachine'

module Server
    def receive_data(data)
        puts data
        send_data("helo\n")
    end
end

EM.run { EM.start_server 'localhost', 8080, Server }

Here we’re calling EM#start_server in our run block. EM#start_server will tell EventMachine to start listening on IP address defined by localhost, port 8080 and will will create an anonymous class and include the module Server for each connection. You could also define Server as a class which inherits from EventMachine::Connection.

It’s worth pointing out, the instantiated class will only exist for a single connection. You won’t be able to store information between requests in the object.

What you can do is pass data into the object when it’s created.

Server Example 2


#!/usr/bin/ruby

require 'rubygems'
require 'eventmachine'

class Server < EventMachine::Connection
    attr_accessor :options, :status

    def receive_data(data)
        puts "#{@status} -- #{data}"
        send_data("helo\n")
    end
end

EM.run do
    EM.start_server 'localhost', 8080, Server do |conn|
        conn.options = {:my => 'options'}
        conn.status = :OK
    end
end

The EM#start_server method will yield to a block passing in the object that will handle the connection. You can then assign any values into that object that you wish.

That’s it for now, my very quick introduction to EventMachine. Hopefully it was useful.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Next Page »