<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: Boof's Code Snippets</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Sun, 27 Jul 2008 00:30:55 GMT</pubDate>
    <description>DZone Snippets: Boof's Code Snippets</description>
    <item>
      <title>RSpec Association Matchers</title>
      <link>http://snippets.dzone.com/posts/show/4721</link>
      <description>Ok, what I essentially wanted to accomplish was something like:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;describe Product, 'with Group' do&lt;br /&gt;&lt;br /&gt;  it 'should belong to group' do&lt;br /&gt;    Product.should belong_to(:product_group)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;describe ProductGroup, 'with Product' do&lt;br /&gt;&lt;br /&gt;  it 'should have many products depending (on group)' do&lt;br /&gt;    ProductGroup.should have_many(:products).depending&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here is the code:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;module AssociationMatchers&lt;br /&gt;&lt;br /&gt;  class AssociationReflection&lt;br /&gt;&lt;br /&gt;    def initialize(type, name)&lt;br /&gt;      @messages = {&lt;br /&gt;        :missing_association =&gt;&lt;br /&gt;          '%s is not associated with %s.',&lt;br /&gt;        :wrong_type =&gt;&lt;br /&gt;          "%s %s %s./nExpected: %s",&lt;br /&gt;        :wrong_options =&gt;&lt;br /&gt;          "Options are incorrect.\nExpected: %s Got: %s",&lt;br /&gt;        :missing_column =&gt;&lt;br /&gt;          "Missing foreign key.\nExpected: %s"&lt;br /&gt;      }&lt;br /&gt;      @name = name&lt;br /&gt;      @expected_type = type&lt;br /&gt;      @expected_options = {}&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    def matches?(target)&lt;br /&gt;      Class === target or&lt;br /&gt;      raise ArgumentError, 'class expected'&lt;br /&gt;&lt;br /&gt;      @target = target&lt;br /&gt;&lt;br /&gt;      unless @assoc = target.reflect_on_association(@name)&lt;br /&gt;        @failure = :missing_association&lt;br /&gt;        return false&lt;br /&gt;      end &lt;br /&gt;&lt;br /&gt;      unless @assoc.macro.eql?(@expected_type)&lt;br /&gt;        @failure = :wrong_type&lt;br /&gt;        return false&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      if @expected_options.any? { |o| @assoc.options[o.first] != o.last }&lt;br /&gt;        @failure = :wrong_options&lt;br /&gt;        return false&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      @column ||= @assoc.primary_key_name || @assoc.klass.name.foreign_key&lt;br /&gt;&lt;br /&gt;      @failure = case @assoc.macro.to_s&lt;br /&gt;      when 'belongs_to'&lt;br /&gt;        if @target.column_names.include?(@column.to_s) then nil&lt;br /&gt;        else&lt;br /&gt;          :missing_column&lt;br /&gt;        end&lt;br /&gt;      when /(?:has_many|has_one)/&lt;br /&gt;        if    @assoc.options[:through] then nil&lt;br /&gt;        elsif @assoc.klass.column_names.include?(@column.to_s) then nil&lt;br /&gt;        else&lt;br /&gt;          :missing_column&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      return @failure.nil?&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def failure_message&lt;br /&gt;      case @failure&lt;br /&gt;      when :missing_association&lt;br /&gt;        @messages[@failure] % [@target.name, @name]&lt;br /&gt;      when :wrong_type&lt;br /&gt;        @messages[@failure] % [&lt;br /&gt;          @target.name,&lt;br /&gt;          @assoc.macro,&lt;br /&gt;          @name,&lt;br /&gt;          @expected_type&lt;br /&gt;        ]&lt;br /&gt;      when :wrong_options&lt;br /&gt;        @messages[@failure] % [&lt;br /&gt;          @expected_options.inspect,&lt;br /&gt;          @assoc.options.inspect&lt;br /&gt;        ]&lt;br /&gt;      when :missing_column&lt;br /&gt;        @messages[@failure] % @column&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    def negative_failure_message&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ### Generic Options&lt;br /&gt;&lt;br /&gt;    def of(class_name)&lt;br /&gt;      class_name = class_name.name if Class === class_name&lt;br /&gt;      @expected_options[:class_name] = class_name&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def for(foreign_key)&lt;br /&gt;      @column = foreign_key&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def due_to(conditions)&lt;br /&gt;      @expected_options[:conditions] = conditions&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def ordered_by(statement)&lt;br /&gt;      @expected_options[:order] = statement&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def including(*models)&lt;br /&gt;      @expected_options[:include] = (models.length == 1)? models.first: models&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;  class BelongsToReflection &lt; AssociationReflection&lt;br /&gt;&lt;br /&gt;    def initialize(name)&lt;br /&gt;      super :belongs_to, name&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def counted(column)&lt;br /&gt;      @expected_options[:counter_cache] = column&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def polymorphic(true_or_false = true)&lt;br /&gt;      @expected_options[:polymorphic] = true_or_false&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  class HasOneReflection &lt; AssociationReflection&lt;br /&gt;&lt;br /&gt;    def initialize(name)&lt;br /&gt;      super :has_one, name&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def as(interface_name)&lt;br /&gt;      @expected_options[:as] = interface_name&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def depending(dependency = true)&lt;br /&gt;      @expected_options[:dependent] = dependency&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def extended_by(mod)&lt;br /&gt;      @expected_options[:extend] = mod&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;  class HasManyReflection &lt; AssociationReflection&lt;br /&gt;&lt;br /&gt;    def initialize(name)&lt;br /&gt;      super :has_many, name&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def as(interface_name)&lt;br /&gt;      @expected_options[:as] = interface_name&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;    def depending(dependency = :destroy)&lt;br /&gt;      @expected_options[:dependent] = dependency&lt;br /&gt;      self&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;  class HasAndBelongsToManyReflection &lt; AssociationReflection&lt;br /&gt;&lt;br /&gt;    def initialize(name)&lt;br /&gt;      super :has_and_belongs_to_many, name&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def belong_to(model)&lt;br /&gt;    BelongsToReflection.new model&lt;br /&gt;  end&lt;br /&gt;  def have_one(model)&lt;br /&gt;    HasOneReflection.new model&lt;br /&gt;  end&lt;br /&gt;  def have_many(models)&lt;br /&gt;    HasManyReflection.new models&lt;br /&gt;  end&lt;br /&gt;  def have_and_belong_to_many(models)&lt;br /&gt;    HasAndBelongsToManyReflection.new models&lt;br /&gt;  end&lt;br /&gt;  alias_method :habtm, :have_and_belong_to_many&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It checks:&lt;br /&gt;* association exists&lt;br /&gt;* association macro&lt;br /&gt;* foreign key exists (except for habtm)&lt;br /&gt;* options match (only a subset is supported)&lt;br /&gt;&lt;br /&gt;Setup:&lt;br /&gt;* put the code in RAILS_ROOT + "/lib/association_matchers.rb"&lt;br /&gt;* put "config.include AssociationMatchers # lib/association_matchers.rb" in your spec_helper.rb configure block&lt;br /&gt;* refactor your model specs...</description>
      <pubDate>Wed, 31 Oct 2007 09:42:07 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/4721</guid>
      <author>boof (Florian A&#223;mann)</author>
    </item>
    <item>
      <title>Prepend a String to a file</title>
      <link>http://snippets.dzone.com/posts/show/4464</link>
      <description>I happen to read a question on the ruby ML that inspired me to monkey patch (not really since this method does not exist...) the file class. I added a method called prepend to the File class. You need to require 'tempfile' or this patch will raise a NameError, imho.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;require 'tempfile'&lt;br /&gt;&lt;br /&gt;class File&lt;br /&gt;  def self.prepend(path, string)&lt;br /&gt;    Tempfile.open File.basename(path) do |tempfile|&lt;br /&gt;      # prepend data to tempfile&lt;br /&gt;      tempfile &lt;&lt; string&lt;br /&gt;&lt;br /&gt;      File.open(path, 'r+') do |file|&lt;br /&gt;        # append original data to tempfile&lt;br /&gt;        tempfile &lt;&lt; file.read&lt;br /&gt;        # reset file positions&lt;br /&gt;        file.pos = tempfile.pos = 0&lt;br /&gt;        # copy all data back to original file&lt;br /&gt;        file &lt;&lt; tempfile.read&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Ideas (unverified):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class FileString &lt; String&lt;br /&gt;  extend Forwardable&lt;br /&gt;&lt;br /&gt;  def initialize(file)&lt;br /&gt;    @file = file.reopen(file.path, 'r+')&lt;br /&gt;    at_exit {@file.close}&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def_delegators :@file, :&lt;&lt;, :pos, :pos=&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;</description>
      <pubDate>Fri, 24 Aug 2007 19:40:07 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/4464</guid>
      <author>boof (Florian A&#223;mann)</author>
    </item>
    <item>
      <title>Find every path and it's value in a Hash</title>
      <link>http://snippets.dzone.com/posts/show/3565</link>
      <description>Extends Hash class with each_path method.&lt;br /&gt;&lt;br /&gt;This method takes a block as argument which is called each time a the recursivly searched Hash returns a key that does not point to another Hash.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;paths = []&lt;br /&gt;complex_hash = Hash[&lt;br /&gt;  :a =&gt; { :aa =&gt; '1', :ab =&gt; '2' },&lt;br /&gt;  :b =&gt; { :ba =&gt; '3', :bb =&gt; '4' }&lt;br /&gt;]&lt;br /&gt;complex_hash.each_path { |path, value| paths &lt;&lt; [ path, value ] }&lt;br /&gt;paths.inspect&lt;br /&gt;# =&gt; "[[\"b/ba/\", \"3\"], [\"b/bb/\", \"4\"], [\"a/aa/\", \"1\"], [\"a/ab/\", \"2\"]]"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Hash&lt;br /&gt;  def each_path&lt;br /&gt;    raise ArgumentError unless block_given?&lt;br /&gt;    self.class.each_path( self ) { |path, object| yield path, object }&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  protected&lt;br /&gt;  def self.each_path( object, path = '', &amp;block )&lt;br /&gt;    if object.is_a?( Hash ) then object.each do |key, value|&lt;br /&gt;        self.each_path value, "#{ path }#{ key }/", &amp;block&lt;br /&gt;      end&lt;br /&gt;    else yield path, object&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 22 Feb 2007 14:54:41 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3565</guid>
      <author>boof (Florian A&#223;mann)</author>
    </item>
    <item>
      <title>SQL-Injection save parser generates ORDER BY statement</title>
      <link>http://snippets.dzone.com/posts/show/3563</link>
      <description>Parses a string and generates an SQL order statement.&lt;br /&gt;&lt;br /&gt;Because it's SQL-Injection save you can put it in your link_to method as :order =&gt; '+name' and then call #parse_order( params[:order] ).&lt;br /&gt;&lt;br /&gt;Examples:&lt;br /&gt;'+name' =&gt; 'name'&lt;br /&gt;'+lastname+firstname' =&gt; 'lastname, firstname'&lt;br /&gt;'+lastname-gender' =&gt; 'lastname, gender DESC'&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;module ActiveRecord&lt;br /&gt;  class Base&lt;br /&gt;    class &lt;&lt; self&lt;br /&gt;&lt;br /&gt;      def parse_order( order )&lt;br /&gt;        order = order.to_s.gsub /([ \+\-][a-z_]+)/ do |match|&lt;br /&gt;          next unless self.column_names.include?( match[1..-1] )&lt;br /&gt;&lt;br /&gt;          case match[0, 1]&lt;br /&gt;          when '-' then "#{ match[1..-1] } DESC, "&lt;br /&gt;          else "#{ match[1..-1] }, "&lt;br /&gt;          end&lt;br /&gt;        end and order[0..-3]&lt;br /&gt;      end&lt;br /&gt;    &lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 22 Feb 2007 12:26:36 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3563</guid>
      <author>boof (Florian A&#223;mann)</author>
    </item>
    <item>
      <title>Try'n'Go: The Last Date</title>
      <link>http://snippets.dzone.com/posts/show/3560</link>
      <description>Extends Date class with a method that return the last Date of a month.&lt;br /&gt;Date#last_of_month takes either a Fixnum or a Time as argument.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;require 'date'&lt;br /&gt;&lt;br /&gt;class Date&lt;br /&gt;  def self.last_of_month( arg = Time.now )&lt;br /&gt;    year = ( arg.is_a? Fixnum ) ? Time.now.year : arg.year&lt;br /&gt;    mon  = ( arg.is_a? Fixnum ) ? arg : ( arg.mon rescue Time.now.mon )&lt;br /&gt;    &lt;br /&gt;    raise ArgumentError unless mon.between?( 1, 12 )&lt;br /&gt;&lt;br /&gt;    begin; Date.new year, mon, mday ||= 31&lt;br /&gt;    rescue ArgumentError; mday -= 1; retry&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 22 Feb 2007 12:11:56 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3560</guid>
      <author>boof (Florian A&#223;mann)</author>
    </item>
  </channel>
</rss>
