Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-3 of 3 total  RSS 

Adding helpful error messages to your Ruby code

This Ruby code raises an error if the XPath query fails because the attribute being queried did not exist for the given element.

  def map_pattr(node, fieldx, valuex)
    begin
    parameter = node.root.elements["parameter[@field='#{fieldx}']"]
    parameter.add_attribute('value', valuex)
    parameter
    
    rescue
      puts 'feedpopulated.rb: map_attr() the field ' + fieldx + ' was not found in params.'
      raise
    end
  end

Notice that a raise statement is used to ensure that the system error message is raised and any further code execution is halted.

Without adding a customized helpful message I would be left scratching my head trying to work out what the following system error message meant.
./feedpopulated.rb:27:in `map_pattr': undefined method `add_attribute' for nil:NilClass (NoMethodError)
     from ./feedpopulated.rb:51:in `create_record'
     from ./feedpopulated.rb:49:in `each'
     from ./feedpopulated.rb:49:in `create_record'
     from ./recordx.rb:91:in `call_create'
     from ./s3fileuploader_handler.rb:14:in `call'
     from ./s3fileuploader_handler.rb:40:in `invoke'
     from ./uploadtwitteraudio.rb:22:in `initialize'
     from /usr/lib/ruby/1.8/rexml/element.rb:890:in `each'
     from /usr/lib/ruby/1.8/rexml/xpath.rb:53:in `each'
     from /usr/lib/ruby/1.8/rexml/element.rb:890:in `each'
     from ./uploadtwitteraudio.rb:18:in `initialize'
     from ./uploadtwitteraudio.rb:72:in `new'
     from ./uploadtwitteraudio.rb:72


Reference: Programming Ruby: The Pragmatic Programmer's Guide - Exceptions, Catch, and Throw [ruby-doc.org]

Display a filtered list using XSLT

Following on from the post A simple XSLT example [dzone.com], this code lists all files which have the type 'rb' (equivalent to ls *.rb).

file: dir.xsl
<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      
    <xsl:template match="dir">
    <div id="articles">
      <ul>
      <xsl:apply-templates select="records/file[@type='rb']"/>
      </ul>
    </div>
    </xsl:template>
    
    <xsl:template match="records/file[@type='rb']">
      <li><xsl:value-of select="."/></li>
    </xsl:template>
    
</xsl:stylesheet>

output:
<div id='articles'>
  <ul>
    <li>projxmlhelper.rb</li>
    <li>feedpopulated.rb</li>
    <li>squrl_handler.rb</li>
    <li>password_handler.rb</li>
    <li>category.rb</li>
    <li>gwd.rb</li>
  </ul>
</div>



*update 11:58am 26-Feb*
Here's a filter I will be using in my projects

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      
    <xsl:template match="dir">
    <div id="articles">
      <ul>
      <xsl:apply-templates select="records/file"/>
      </ul>
    </div>
    </xsl:template>
    
    <xsl:template match="records/file">
      <xsl:if test="@type=$type">
        <li><xsl:value-of select="."/></li>
      </xsl:if>
    </xsl:template>
    
</xsl:stylesheet>

Specifying default values with Ruby's attr_reader and attr_accessor

Dependency injection in Ruby is as easy as falling off a log. As Jamis Buck has pointed out, DI is a good thing, but DI frameworks for Ruby are overkill. The language makes them unnecessary.

Here's how to enhance attr_reader and attr_accessor so that they can receive an options hash for specifying the default value of an attribute.

module AttrWithDefaultExtension
  
  module ClassMethods
    
    def attr_accessor(*args)
      attrs, attrs_with_defaults = split_for_last_hash(args)
      attrs_with_defaults.each do |name, default|
        attr_reader_with_default name, default
        attr_writer              name
      end
      
      super(*attrs)
    end
    
    def attr_reader(*args)
      attrs, attrs_with_defaults = split_for_last_hash(args)
      attrs_with_defaults.each do |name, default|
        attr_reader_with_default name, default
      end
      
      super(*attrs)
    end
    
  private
    
    def attr_reader_with_default(name, default)
      define_method(name) do
        unless instance_variable_defined?("@#{name}")
          default = default.call(self) if default.kind_of?(Proc)
          instance_variable_set "@#{name}", default
        end
        instance_variable_get "@#{name}"
      end
    end
    
    def split_for_last_hash(args)
      if args.last.kind_of?(Hash)
        [args[0...-1], args.last]
      else
        [args, {}]
      end
    end
    
  end
  
  def self.included(other_module)
    other_module.extend ClassMethods
  end
  
end

class Object; include AttrWithDefaultExtension; end


Here are the unit tests. They demonstrate not only the enhanced behavior of attr_reader and attr_accessor, but also that the standard behavior remains unbroken.

require 'test/unit'

module AttrWithDefaultExtensionTest
  
  class TwoStandardAttrReaders < Test::Unit::TestCase
    
    attr_reader :foo, :baz
    
    def test_should_not_define_first_instance_variable
      assert_equal false, instance_variable_defined?(:@foo)
    end
    
    def test_should_return_first_instance_variable_when_sent_first_attr_reader
      @foo = 'bar'
      assert_equal 'bar', foo
    end
    
    def test_should_not_define_second_instance_variable
      assert_equal false, instance_variable_defined?(:@baz)
    end
    
    def test_should_return_second_instance_variable_when_sent_second_attr_reader
      @baz = 'bat'
      assert_equal 'bat', baz
    end
    
  end
  
  class TwoStandardAttrAccessors < Test::Unit::TestCase
    
    attr_accessor :foo, :baz
    
    def test_should_not_define_first_instance_variable
      assert_equal false, instance_variable_defined?(:@foo)
    end
    
    def test_should_return_first_instance_variable_when_sent_first_attr_reader
      @foo = 'bar'
      assert_equal 'bar', foo
    end
    
    def test_should_set_first_instance_variable_when_sent_first_attr_writer
      self.foo = 'bar'
      assert_equal 'bar', @foo
    end
    
    def test_should_not_define_second_instance_variable
      assert_equal false, instance_variable_defined?(:@baz)
    end
    
    def test_should_return_second_instance_variable_when_sent_second_attr_reader
      @baz = 'bat'
      assert_equal 'bat', baz
    end
    
    def test_should_set_second_instance_variable_when_sent_second_attr_writer
      self.baz = 'bat'
      assert_equal 'bat', @baz
    end
    
  end
  
  class TwoStandardAttrReadersAndADefault < Test::Unit::TestCase
    
    attr_reader :foo, :baz, :blit => 'blat'
    
    def test_should_not_define_first_instance_variable
      assert_equal false, instance_variable_defined?(:@foo)
    end
    
    def test_should_return_first_instance_variable_when_sent_first_attr_reader
      @foo = 'bar'
      assert_equal 'bar', foo
    end
    
    def test_should_not_define_second_instance_variable
      assert_equal false, instance_variable_defined?(:@baz)
    end
    
    def test_should_return_second_instance_variable_when_sent_second_attr_reader
      @baz = 'bat'
      assert_equal 'bat', baz
    end
    
    def test_should_not_define_third_instance_variable
      assert_equal false, instance_variable_defined?(:@blit)
    end
    
    def test_should_set_third_instance_variable_when_sent_third_attr_reader
      blit
      assert_equal 'blat', @blit
    end
    
    def test_should_not_set_third_instance_variable_if_already_set_when_sent_third_attr_reader
      @blit = 'splat'
      assert_equal 'splat', blit
    end
    
  end
  
  class TwoStandardAttrAccessorsAndADefault < Test::Unit::TestCase
    
    attr_accessor :foo, :baz, :blit => 'blat'
    
    def test_should_not_define_first_instance_variable
      assert_equal false, instance_variable_defined?(:@foo)
    end
    
    def test_should_return_first_instance_variable_when_sent_first_attr_reader
      @foo = 'bar'
      assert_equal 'bar', foo
    end
    
    def test_should_set_first_instance_variable_when_sent_first_attr_writer
      self.foo = 'bar'
      assert_equal 'bar', @foo
    end
    
    def test_should_not_define_second_instance_variable
      assert_equal false, instance_variable_defined?(:@baz)
    end
    
    def test_should_return_second_instance_variable_when_sent_second_attr_reader
      @baz = 'bat'
      assert_equal 'bat', baz
    end
    
    def test_should_set_second_instance_variable_when_sent_second_attr_writer
      self.baz = 'bat'
      assert_equal 'bat', @baz
    end
    
    def test_should_not_define_third_instance_variable
      assert_equal false, instance_variable_defined?(:@blit)
    end
    
    def test_should_set_third_instance_variable_when_sent_third_attr_reader
      blit
      assert_equal 'blat', @blit
    end
    
    def test_should_not_set_third_instance_variable_if_already_set_before_sent_third_attr_reader
      @blit = 'splat'
      assert_equal 'splat', blit
    end
    
    def test_should_set_third_instance_variable_when_sent_third_attr_writer
      self.blit = 'splat'
      assert_equal 'splat', @blit
    end
    
  end
  
  class AProcDefault < Test::Unit::TestCase
    
    attr_accessor :my_object_id => Proc.new { |obj| obj.object_id }
    
    def test_should_not_define_instance_variable
      assert_equal false, instance_variable_defined?(:@my_object_id)
    end
    
    def test_should_set_instance_variable_to_result_of_proc_when_sent_attr_reader
      my_object_id
      assert_equal object_id, @my_object_id
    end
    
    def test_should_not_set_instance_variable_if_already_set_before_sent_attr_reader
      @my_object_id = 'foo'
      assert_equal 'foo', my_object_id
    end
    
    def test_should_set_instance_variable_when_sent_attr_writer
      self.my_object_id = 'foo'
      assert_equal 'foo', @my_object_id
    end
    
  end
  
  class AProcWithinAProcDefault < Test::Unit::TestCase
    
    attr_accessor :my_proc => Proc.new { Proc.new { } }
    
    def test_should_not_define_instance_variable
      assert_equal false, instance_variable_defined?(:@my_proc)
    end
    
    def test_should_set_instance_variable_to_result_of_outer_proc_when_sent_attr_reader
      my_proc
      assert_kind_of Proc, @my_proc
    end
    
    def test_should_not_set_instance_variable_if_already_set_before_sent_attr_reader
      @my_proc = 'foo'
      assert_equal 'foo', my_proc
    end
    
    def test_should_set_instance_variable_when_sent_attr_writer
      self.my_proc = 'foo'
      assert_equal 'foo', @my_proc
    end
    
  end
  
end
« Newer Snippets
Older Snippets »
Showing 1-3 of 3 total  RSS