<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: Timmorgan's Code Snippets</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Thu, 21 Aug 2008 16:36:12 GMT</pubDate>
    <description>DZone Snippets: Timmorgan's Code Snippets</description>
    <item>
      <title>Automatic Expiration of Rails Action Caching</title>
      <link>http://snippets.dzone.com/posts/show/5776</link>
      <description>Would love to get some feedback on this...&lt;br /&gt;&lt;br /&gt;No doubt, 5 minutes after posting this, someone will tell me of the built-in Rails way of doing this, but alas I could not find it.&lt;br /&gt;&lt;br /&gt;Usage looks like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class PeopleController &lt; ApplicationController&lt;br /&gt;  caches_action :show, :for =&gt; 1.hour, :cache_path =&gt; Proc.new { |c| "people/#{c.params[:id]}_for_#{Person.logged_in.id}" }&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The ":for =&gt; 1.hour" part is where the magic happens.&lt;br /&gt;&lt;br /&gt;Basically, this bit of code adds a before_filter that checks the last modified time of the cache entry, and expires it if it is older than the specified time period.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;module ActionController&lt;br /&gt;  module Caching&lt;br /&gt;    module Fragments&lt;br /&gt;      # expire a cache key only if the block returns true or&lt;br /&gt;      # if the age of the fragment is more than the specified age argument.&lt;br /&gt;      def expire_fragment_by_mtime(key, age=nil, &amp;block)&lt;br /&gt;        block = Proc.new { |m| m &lt; age.ago } unless block_given?&lt;br /&gt;        if (m = cache_store.mtime(fragment_cache_key(key))) and block.call(m)&lt;br /&gt;          expire_fragment(key)&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    module Actions&lt;br /&gt;      module ClassMethods&lt;br /&gt;        # adds an option :for&lt;br /&gt;        # caches_action :show, :for =&gt; 2.hours, :cache_path =&gt; ...&lt;br /&gt;        # :cache_path is required, unfortunately&lt;br /&gt;        def caches_action_with_for(*actions)&lt;br /&gt;          original_actions = actions.clone&lt;br /&gt;          options = actions.extract_options!&lt;br /&gt;          if for_time = options.delete(:for)&lt;br /&gt;            cache_path = options[:cache_path]&lt;br /&gt;            before_filter do |controller|&lt;br /&gt;              cache_path = cache_path.call(controller) if cache_path.respond_to?(:call)&lt;br /&gt;              controller.expire_fragment_by_mtime(cache_path, for_time)&lt;br /&gt;            end&lt;br /&gt;          end&lt;br /&gt;          caches_action_without_for(*original_actions)&lt;br /&gt;        end&lt;br /&gt;        alias_method_chain :caches_action, :for&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Add a method to grab the last modified time of the cache key.&lt;br /&gt;# If you use a store other than the FileStore, you'll need to add&lt;br /&gt;# a method like this to your store.&lt;br /&gt;module ActiveSupport&lt;br /&gt;  module Cache&lt;br /&gt;    class FileStore&lt;br /&gt;      def mtime(name)&lt;br /&gt;        File.mtime(real_file_path(name)) rescue nil&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 16 Jul 2008 03:21:22 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5776</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>nslookup.rb</title>
      <link>http://snippets.dzone.com/posts/show/5720</link>
      <description>Does a web-based DNS lookup. Useful for those of us behind corporate firewalls that block fun sites based on DNS queries, i.e. OpenDNS.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env ruby&lt;br /&gt;&lt;br /&gt;LOOKUP_URL = 'http://toolbar.netcraft.com/site_report?url=%s'&lt;br /&gt;MATCH_RE = /&lt;td&gt;&lt;b&gt;IP address&lt;\/b&gt;&lt;\/td&gt;&lt;td.*?&gt;([\d\.]+)&lt;\/td&gt;/&lt;br /&gt;HOSTS_FILE_PATH = '/etc/hosts'&lt;br /&gt;&lt;br /&gt;require 'open-uri'&lt;br /&gt;&lt;br /&gt;host = ARGV.select { |arg| arg !~ /^\-/ }.first&lt;br /&gt;update_hosts_file = ARGV.select { |arg| arg == '--hosts' }.any?&lt;br /&gt;&lt;br /&gt;if open(LOOKUP_URL % host).read =~ MATCH_RE&lt;br /&gt;  ip = $1&lt;br /&gt;  puts ip&lt;br /&gt;  if update_hosts_file&lt;br /&gt;    File.open(HOSTS_FILE_PATH, 'a') do |file|&lt;br /&gt;      file.write("\n#{ip} #{host}")&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;else&lt;br /&gt;  puts 'There was an error looking up this host.'&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;./nslookup.rb youtube.com&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To add the entry to your hosts file:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;sudo ./nslookup.rb youtube.com --hosts&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 02 Jul 2008 20:47:57 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5720</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Trac Wiki to GitHub Wiki</title>
      <link>http://snippets.dzone.com/posts/show/5304</link>
      <description>A rough start of a script to help convert the wiki syntax of Trac pages to GitHub-friendly syntax.&lt;br /&gt;&lt;br /&gt;Some TLC is still needed on each output page, but better than doing it all by hand.&lt;br /&gt;&lt;br /&gt;Project lives here: &lt;a href="http://github.com/seven1m/trac_wiki_to_github"&gt;github.com/seven1m/trac_wiki_to_github&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/env ruby&lt;br /&gt; &lt;br /&gt;TRAC_DB_PATH = 'trac.db'&lt;br /&gt;OUT_PATH = 'wiki'&lt;br /&gt;GITHUB_WIKI_URL = '/seven1m/onebody/wikis/'&lt;br /&gt; &lt;br /&gt;require 'sqlite3'&lt;br /&gt; &lt;br /&gt;db = SQLite3::Database.new(TRAC_DB_PATH)&lt;br /&gt;pages = db.execute('select name, text from wiki w2 where version = (select max(version) from wiki where name = w2.name);')&lt;br /&gt; &lt;br /&gt;pages.each do |title, body|&lt;br /&gt;  File.open(File.join(OUT_PATH, title.gsub(/\s/, '')), 'w') do |file|&lt;br /&gt;    body.gsub!(/\{\{\{([^\n]+?)\}\}\}/, '&lt;code&gt;\1&lt;/' + 'code&gt;')&lt;br /&gt;    body.gsub!(/\{\{\{(.+?)\}\}\}/m, '&lt;pre&gt;&lt;code&gt;\1&lt;/' + 'code&gt;&lt;/pre&gt;')&lt;br /&gt;    body.gsub!(/====\s(.+?)\s====/, 'h4. \1')&lt;br /&gt;    body.gsub!(/===\s(.+?)\s===/, 'h3. \1')&lt;br /&gt;    body.gsub!(/==\s(.+?)\s==/, 'h2. \1')&lt;br /&gt;    body.gsub!(/=\s(.+?)\s=[\s\n]*/, '')&lt;br /&gt;    body.gsub!(/\[(http[^\s\[\]]+)\s([^\[\]]+)\]/, '"\2":\1')&lt;br /&gt;    body.gsub!(/\[([^\s]+)\s(.+)\]/, '"\2":' + GITHUB_WIKI_URL + '\1')&lt;br /&gt;    body.gsub!(/([^"\/\!])(([A-Z][a-z0-9]+){2,})/, '\1[[\2]]')&lt;br /&gt;    body.gsub!(/\!(([A-Z][a-z0-9]+){2,})/, '\1')&lt;br /&gt;    body.gsub!(/'''(.+)'''/, '*\1*')&lt;br /&gt;    body.gsub!(/''(.+)''/, '_\1_')&lt;br /&gt;    body.gsub!(/^\s\*/, '*')&lt;br /&gt;    body.gsub!(/^\s\d\./, '#')&lt;br /&gt;    file.write(body)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 02 Apr 2008 02:05:02 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5304</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Rails Notice/Warning Flash Message</title>
      <link>http://snippets.dzone.com/posts/show/5271</link>
      <description>Somewhat lame, but handy nonetheless.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;% if flash[:warning] or flash[:notice] %&gt;&lt;br /&gt;  &lt;div id="notice" &lt;% if flash[:warning] %&gt;class="warning"&lt;% end %&gt;&gt;&lt;br /&gt;    &lt;%= flash[:warning] || flash[:notice] %&gt;&lt;br /&gt;  &lt;/div&gt;&lt;br /&gt;  &lt;script type="text/javascript"&gt;&lt;br /&gt;    setTimeout("new Effect.Fade('notice');", 15000)&lt;br /&gt;  &lt;/script&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Sun, 23 Mar 2008 00:01:03 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5271</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Copy Public Key To Host In One Line</title>
      <link>http://snippets.dzone.com/posts/show/5258</link>
      <description>&lt;code&gt;&lt;br /&gt;ssh username@host "echo `cat ~/.ssh/id_dsa.pub` &gt;&gt; ~/.ssh/authorized_keys"&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 19 Mar 2008 18:23:53 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5258</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Ruby Array#every method</title>
      <link>http://snippets.dzone.com/posts/show/5222</link>
      <description>Chunks an array into smaller arrays of the specified size.&lt;br /&gt;&lt;br /&gt;Updated: Turns out a similar method is available in Rails called Array#in_groups_of. But still, I will leave this up because it seems elegant enough to me.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Array&lt;br /&gt;  def every(count)&lt;br /&gt;    chunks = []&lt;br /&gt;    each_with_index do |item, index|&lt;br /&gt;      chunks &lt;&lt; [] if index % count == 0&lt;br /&gt;      chunks.last &lt;&lt; item&lt;br /&gt;    end&lt;br /&gt;    chunks&lt;br /&gt;  end&lt;br /&gt;  alias / every&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(1..7).to_a.every(2)&lt;br /&gt;# =&gt; [[1, 2], [3, 4], [5, 6], [7]]&lt;br /&gt;&lt;br /&gt;(1..7).to_a / 3&lt;br /&gt;# =&gt; [[1, 2, 3], [4, 5, 6], [7]]&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 13 Mar 2008 02:46:54 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5222</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Rails MySQL/SQLite convenience methods</title>
      <link>http://snippets.dzone.com/posts/show/5148</link>
      <description>Usage:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  Person.find :all, :conditions =&gt; ["#{sql_year 'birthday'} &gt;= ?", year]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SQLITE = true # or false&lt;br /&gt;&lt;br /&gt;def sql_concat(*args)&lt;br /&gt;  SQLITE ? args.join(' || ') : "CONCAT(#{args.join(', ')})"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def sql_lcase(expr)&lt;br /&gt;  SQLITE ? "LOWER(#{expr})" : "LCASE(#{expr})"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def sql_year(expr)&lt;br /&gt;  SQLITE ? "CAST(STRFTIME('%y', #{expr}) as 'INTEGER')" : "YEAR(#{expr})"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def sql_month(expr)&lt;br /&gt;  SQLITE ? "CAST(STRFTIME('%m', #{expr}) as 'INTEGER')" : "MONTH(#{expr})"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def sql_day(expr)&lt;br /&gt;  SQLITE ? "CAST(STRFTIME('%d', #{expr}) as 'INTEGER')" : "DAY(#{expr})"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def sql_now&lt;br /&gt;  SQLITE ? "CURRENT_TIMESTAMP" : "NOW()"&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Mon, 18 Feb 2008 02:57:36 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5148</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Rails Array#add_condition Method</title>
      <link>http://snippets.dzone.com/posts/show/5147</link>
      <description>Lets you add a condition to a set of ActiveRecord conditions easily like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  conditions = ['active = ? and type = ?', true, 2]&lt;br /&gt;  conditions.add_condition ['person_id = ?', 345]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Array&lt;br /&gt;  def add_condition(condition, conjunction='and')&lt;br /&gt;    if condition.is_a? Array&lt;br /&gt;      if self.empty?&lt;br /&gt;        (self &lt;&lt; condition).flatten!&lt;br /&gt;      else&lt;br /&gt;        self[0] += " #{conjunction} " + condition.shift&lt;br /&gt;        (self &lt;&lt; condition).flatten!&lt;br /&gt;      end&lt;br /&gt;    elsif condition.is_a? String&lt;br /&gt;      self[0] += " #{conjunction} " + condition&lt;br /&gt;    else&lt;br /&gt;      raise "don't know how to handle this condition type"&lt;br /&gt;    end&lt;br /&gt;    self&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Mon, 18 Feb 2008 02:54:44 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5147</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Marshalize (Cache) ActiveRecord Query Results</title>
      <link>http://snippets.dzone.com/posts/show/5058</link>
      <description>A quick way to cache results in a file and read from the file on subsequent requests instead of the database. Makes the initial query a bit slower, but later queries *much* faster.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class MyCachedModel &lt; ActiveRecord::Base&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    alias_method :rails_original_find_by_sql, :find_by_sql&lt;br /&gt;    def find_by_sql(sql)&lt;br /&gt;      cache_filename = Base64.encode64(sql)&lt;br /&gt;      if File.exists? cache_filename&lt;br /&gt;        Marshal.load(File.open(cache_filename))&lt;br /&gt;      else&lt;br /&gt;        Marshal.dump(records = rails_original_find_by_sql(sql), File.open(cache_filename, 'w'))&lt;br /&gt;        return records&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 31 Jan 2008 01:37:39 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5058</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Ruby DBF Library Fixes</title>
      <link>http://snippets.dzone.com/posts/show/5050</link>
      <description>A handful of fixes/enhancements for the "dbf" Rubygem.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# example.rb&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'dbf'&lt;br /&gt;require 'dbf_fixes'&lt;br /&gt;&lt;br /&gt;table = DBF::Table.new('/path/to/table.dbf', :in_memory =&gt; false)&lt;br /&gt;table.each_record do |record|&lt;br /&gt;  # do something here&lt;br /&gt;  # with in_memory=&gt;false tables, each_record is much more efficient&lt;br /&gt;  # because it reads directly from disk &lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# dbf_fixes.rb&lt;br /&gt;module DBF&lt;br /&gt;  class Record&lt;br /&gt;    private&lt;br /&gt;&lt;br /&gt;    # fix bug in DBF code (or workaround bug in FoxPro dbf files; I don't know :-)&lt;br /&gt;    def initialize_values(columns)&lt;br /&gt;      columns.each do |column|&lt;br /&gt;        case column.type&lt;br /&gt;        when 'I' # added by Tim - I don't understand this much, but it seems to work&lt;br /&gt;          @attributes[column.name] = @data.read(column.length).unpack("I").first&lt;br /&gt;        when 'N' # number&lt;br /&gt;          @attributes[column.name] = column.decimal.zero? ? unpack_string(column).to_i : unpack_string(column).to_f&lt;br /&gt;        when 'D' # date&lt;br /&gt;          raw = unpack_string(column).strip&lt;br /&gt;          unless raw.empty?&lt;br /&gt;            begin&lt;br /&gt;              parts = raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}&lt;br /&gt;              @attributes[column.name] = Time.gm(*parts)&lt;br /&gt;            rescue&lt;br /&gt;              parts = raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}&lt;br /&gt;              @attributes[column.name] = Date.new(*parts)&lt;br /&gt;            end&lt;br /&gt;          end&lt;br /&gt;        when 'M' # memo&lt;br /&gt;          starting_block = unpack_string(column).to_i&lt;br /&gt;          @attributes[column.name] = read_memo(starting_block)&lt;br /&gt;        when 'L' # logical&lt;br /&gt;          @attributes[column.name] = unpack_string(column) =~ /^(y|t)$/i ? true : false&lt;br /&gt;        else&lt;br /&gt;          @attributes[column.name] = unpack_string(column).strip&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # don't know why, but accessors stopped working for me.&lt;br /&gt;    def define_accessors&lt;br /&gt;      @table.columns.each do |column|&lt;br /&gt;        underscored_column_name = underscore(column.name)&lt;br /&gt;        if @table.options[:accessors]&lt;br /&gt;          self.class.send :define_method, underscored_column_name do&lt;br /&gt;            @attributes[column.name]&lt;br /&gt;          end&lt;br /&gt;          @@accessors_defined = true&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  class Table&lt;br /&gt;    # more efficient iterator (so we don't load everything)&lt;br /&gt;    def each_record&lt;br /&gt;      if options[:in_memory] and @records&lt;br /&gt;        @records.each { |r| yield(r) }&lt;br /&gt;      else&lt;br /&gt;        0.upto(@record_count - 1) do |n|&lt;br /&gt;          seek_to_record(n)&lt;br /&gt;          yield(DBF::Record.new(self)) unless deleted_record?&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Tue, 29 Jan 2008 18:01:56 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5050</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
  </channel>
</rss>
