Skip to content

Instantly share code, notes, and snippets.

@knowtheory
Created March 6, 2011 22:19
Show Gist options
  • Select an option

  • Save knowtheory/857779 to your computer and use it in GitHub Desktop.

Select an option

Save knowtheory/857779 to your computer and use it in GitHub Desktop.
require 'dm-core'
require 'dm-validations'
require 'dm-tags'
module Confoosed
class Speaker
include DataMapper::Resource
property :id, Serial
property :name, String, :length => 255
property :url, String, :length => 255, :format => :url
has n, :sessions, :through => Resource
end
end
module Confoosed
class Session
include DataMapper::Resource
property :id, Serial
property :name, String, :length => 255
property :url, String, :length => 255, :format => :url
property :start_at, DateTime
property :end_at, DateTime
has n, :speakers, :through => Resource
has_tags # comes from dm-tags
end
end
DataMapper.setup(:default, 'postgres://knowtheory@localhost:5432/confoosed_development')
DataMapper.auto_migrate!
require 'open-uri'
require 'nokogiri'
require 'date'
schedule_data = Nokogiri::HTML(open("http://confoo.ca/en/2011/schedule"))
dates = schedule_data.css('#schedule h2').map do |h2|
month, day, year = h2.text.split(/[\(\)]/)[1].split('/').map(&:to_i)
year += 2000
[year, month, day] # list date components in descending order for DateTime creation
end
date_index = 0 # no way to keep days and sessions in sync other than co-iteration.
sessions = schedule_data.css('#schedule .schedule_day').map do |day|
days_sessions = day.css('tr').map do |slot| # have to assign day_sessions because of co-iteration
# table header for each row contains only a start time and an end time.
start_at, end_at = slot.css('th').text.split.map do |slot_time|
DateTime.new(*dates[date_index], *slot_time.split(":").map(&:to_i), 0, 5.0/24)
end
if slot.css('div').size == 0 # sessions have divs, breaks don't
{ :name => slot.css('td').text.strip, :start_at => start_at, :end_at => end_at }
else
# some rows have fewer than 8 sessions, and so contain empty tds. discard them and
# return a hash for each session
slot.css('td').reject{ |cell| cell.text =~ /\A\W+\z/ }.map do |session|
name_data = session.css('div.session a').first # there is always 1 and only 1 <a> per session
{ :name => name_data.text.strip,
:url => name_data.attributes['href'].text,
:tags => session.css('div.tags span.tag').map { |tag| Tag.first_or_new(:name=>tag.text.strip.gsub(/\s+/,' ')) },
:speakers => session.css('div.speaker a').map do |speaker_data|
{ :name => speaker_data.text.strip, :url => speaker_data.attributes['href'].text }
end,
:start_at => start_at,
:end_at => end_at
}
end
end
end
date_index += 1
days_sessions
end.flatten
# Todo: merge record creation into loop above, and eliminate explicit index using Array#each_with_index
sessions.each do |session|
options = session.dup
options[:speakers] = session[:speakers].map{ |s| Confoosed::Speaker.first_or_new(s) } if session[:speakers]
options[:tags] = session[:tags].map{ |t| Tag.first_or_new(t) } if session[:tag]
Confoosed::Session.create(options)
end
Confoosed::Session.all("start_at.gte" => Date.new(2011, 3, 8), "end_at.lte" => Date.new(2011, 3, 8).next_day)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment