Archive for February, 2007

Javascript IE PNG fix

Monday, February 26th, 2007

I adapted the pngfix.js to be rails friendly. Not that I should be using image tags anyway.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var arVersion = navigator.appVersion.split("MSIE");
var version = parseFloat(arVersion[1]);

if ((version >= 5.5) && (document.body.filters)) {        
  var i;
  var length = document.images.length;
    for(i = 0; i < length; i++) {
      var img = document.images[i];
      var re = /\w+\.[Pp][Nn][Gg]\w*/;
      if (img && re.exec(img.src)) {
        var imgTitle = img.title ? "title='" + img.title + "' " : "title='" + img.alt + "' ";
        imgStyle = img.parentElement.href ? "cursor:pointer;" : "";
        imgStyle += "width:" + img.width + "px; height:" + img.height + "px;";
        imgStyle += "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader (src=\'" + img.src + "\', sizingMethod='scale');";
                
        var strNewHTML = "&lt;span " + imgTitle + " style=\"display:inline-block; " + imgStyle + " \"></span>";

        img.outerHTML = strNewHTML;
        i = i - 1;
    }
  }
}

download

Then add this somewhere in your <head>

1
2
3
<!--[if lt IE 7]>
<script defer type="text/javascript" src="/javascripts/pngfix.js"></script>
<![endif]-->

The only other requirement is you specify a width and height on your image_tags


<%= image_tag("fam/date.png", :alt => "ical", :width => "16px", :height => "16px") %>

Though you should use CSS for most images, this is a fast way to make your png’s work in IE6.

Fragment Cache Store with TTL

Wednesday, February 21st, 2007

I wanted to use a fragment cache, but I didn’t want to deal with expiring it. So I just made a self-expiring cache based on a TTL.

The fragment cache store just wants 4 methods: read, write, delete, delete_matched

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Cache::MemStore

  attr_reader :ttl, :auto_expire
    
  def initialize(options = {})
    @ttl = options[:ttl] || 10.minutes
    @cache = {}
  end
    
  def expire(pattern)
    @cache.each { |key, val| delete key if key =~ pattern }
  end
  
  def read(key, options)
    delete(key, options) and return if is_expired?(key)
    return @cache[key][:content] if @cache.has_key? key
  end
  
  def write(key, content, options)
    @cache[key] = { :content => content, :created_on => Time.now }
  end
  
  def delete_matched(pattern, options)
    expire pattern
  end
  
  def delete(key, options)
    @cache.delete key
  end
  
  def is_expired?(key)
    if @cache.has_key? key
      created_on = @cache[key][:created_on]
      return Time.now > (created_on + @ttl)
    end
  end
  
end

Then in your environment.rb put:


ActionController::Base.fragment_cache_store = Cache::MemStore.new(:ttl => 10.minutes)

railsbench gave me the following results:

page request                                      total  stddev%     r/s    ms/r
with cache: /                                   7.23471   2.8012   13.82   72.35
nocache:    /                                  25.81057   0.6966    3.87  258.11

Creating iCalendar files in Ruby

Friday, February 16th, 2007

Using the iCalendar ruby library (gem install icalendar):

From the Show model, I added a method to create an event:

1
2
3
4
5
6
7
8
9
10
11
class Show < ActiveRecord::Base
...
  def to_ical_event
    event = Icalendar::Event.new    
    event.dtstart = time ? time.to_datetime : date
    event.dtstamp = created_at.to_datetime
    event.summary = "The title"
    event.description = "The description"
    event.uid = "show-#{id}"   
  end
end
  • dtstart takes a Date or DateTime object (see Ruby cookbook recipe chapter 3.9 for to_datetime method).

From the Venue model, I added a method to create the calendar and add all the show events:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Venue < ActiveRecord::Base
  has_many :shows  
...
  def to_ical
    ical = Icalendar::Calendar.new
    ical.product_id = "-//dclicio.us//iCal 1.0//EN"
    ical.custom_property("X-WR-CALNAME;VALUE=TEXT", name)
    ical.custom_property("X-WR-TIMEZONE;VALUE=TEXT", "US/Eastern")
    shows.each do |show|
      event = show.to_ical_event
      ical.add_event(event)
    end
    ical
  end
end
  • The X-WR custom properties are read by iCal and by google calendar.

Then a task to iterate through the venues creating the ics files:

1
2
3
4
5
6
Venue.find(:all, :include => [ :shows ]).each do |venue|
  ical = venue.to_ical       
  file = File.new("/tmp/#{venue.name}.ics", "w")
  file.write(ical.to_ical) # Allow myself to ... introduce ... myself :/
  file.close
end

An ics file looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BEGIN:VCALENDAR
X-WR-CALNAME;VALUE=TEXT:Black cat
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:-//dclicio.us//iCal 1.0//EN
X-WR-TIMEZONE;VALUE=TEXT:US/Eastern
BEGIN:VEVENT
UID:dclicio.us-243
DESCRIPTION:with \nhttp://dclicio.us
SUMMARY:
DTSTART:20070117
DTSTAMP:040425
SEQ:0
END:VEVENT
END:VCALENDAR

I then surface these files in public/ical/ and add a ProxyPass /ical ! so apache can serve em up straight without hitting mongrel.

Check out dclicio.us to see it in action.