Custom YAML Emitter

Friday, March 23, 2007 by Nate Murray.

Rational Numbers

Just recently I needed to store a rational number in a database. YAML is perfect for this sort of thing. Unfortunately there isn’t a built in to_yaml for the standard Rational class.


  require 'yaml'

  rat = Rational(4,3)  # => Rational(4, 3)
  rat.to_s             # => "4/3"

  y = YAML.dump(rat)   # => "--- !ruby/object:Rational 4/3\n"

  back = YAML.load(y)  # => Rational(nil, nil)

Notice that rat gets emitted as a vanilla ruby object with class Rational but then the emitter just converts rat into a string and we get "4/3" appended to the YAML output. Because the YAML parser doesn’t know what do to with the string "4/3" we get back a Rational object but it doesn’t have its numerator or denominator set. We want back to be set to Rational(4, 3), just like the original object.

Register Your Class

What we need to do is register our Rational class with YAML so that it knows how to emit and parse our specific type of object.

We can specify our yaml_type by defining a method to_yaml_type. We then register with YAML by calling YAML::add_domain_type and passing it a block. The YAML parser will then call this block when it tries to emit an object of this matching type.

Notice below that YAML::add_domain_type yields two variables type and val. type is the YAML type we specified with to_yaml_type and the val is the value that was stored during the YAML creation process.



  require 'yaml'
  class Rational
    def to_yaml_type; "!pasadenarb.com,2007-03-23/rational"; end
  end

  YAML::add_domain_type( "pasadenarb.com,2007-03-23", "rational") do  |type, val|
    type                  # => "tag:pasadenarb.com,2007-03-23:rational"
    val                   # => "4/3"
  end

  rat  = Rational(4,3)    # => Rational(4, 3)
  yam  = YAML.dump(rat)   # => "--- !pasadenarb.com,2007-03-23/rational 4/3\n"
  back = YAML.load(yam)   # => "4/3" 



Simple Parsing

Notice here that YAML.load returned the value returned by the block we passed add_domain_type. In this case it is val("4/3"). We are a little closer to our goal, but back is still not a Rational, it’s a String. What we need to do is improve on the block we are passing to add_domain_type.

We are getting the string "4/3" in val so we can derive the numerator and denominator from that string and then return a Rational number from that string.


  require 'yaml'
  class Rational
    def to_yaml_type; "!pasadenarb.com,2007-03-23/rational"; end
  end

  YAML::add_domain_type( "pasadenarb.com,2007-03-23", "rational") do  |type, val|
    num, den = val.split("\/")       # => ["4", "3"]
    Rational(num.to_i, den.to_i)
  end

  rat  = Rational(4,3)     # => Rational(4, 3)
  yam  = YAML.dump(rat)    # => "--- !pasadenarb.com,2007-03-23/rational 4/3\n"
  back = YAML.load(yam)    # => Rational(4, 3)


Notice that back is Rational(4, 3), just as we originally wanted.

However this method is not as perfect as it could be. In this case we are able to derive the attributes we need pretty easily, but what if we had a more complicated object that did not store all of its attributes if you call #to_s on the object? What we need is more control over the YAML creation process. Thankfully that power is available by creating our own #to_yaml method.

Advanced Emitting

If you look at the #to_yaml method below you will see that we are iterating through the instance_variables and setting the key to be the instance variable name and the value is the instance variable value.

Then when we need to create the Rational number from that we just grab the hash keys from val.


  require 'yaml'
  class Rational

    def to_yaml_type; "!pasadenarb.com,2007-03-23/rational"; end

    def to_yaml( opts = {} )
      YAML.quick_emit( self.object_id, opts ) { |out|
        out.map( taguri, to_yaml_style ) { |map|
          instance_variables.sort.each { |iv|
            map.add( iv[1..-1], instance_eval( iv ) )
          }
        }
      }
    end

  end

  YAML::add_domain_type( "pasadenarb.com,2007-03-23", "rational") do  |type, val|
    num, den = val["numerator"], val["denominator"]  # => [4, 3]
    Rational(num.to_i, den.to_i)
  end

  rat  = Rational(4,3)    # => Rational(4, 3)
  yam  = YAML.dump(rat)   # => "--- !pasadenarb.com,2007-03-23/rational \ndenominator: 3\nnumerator: 4\n"
  back = YAML.load(yam)   # => Rational(4, 3)


Conclusion

As you can see YAML is a very powerful way to get complex objects into strings. There are a few other shortcuts to get custom objects into YAML such as defining #to_yaml_properties. If you are interested in doing something simple, I’d start by looking here.

Labels: , ,

Introduction to Bindings

Tuesday, March 20, 2007 by Nate Murray.

The Pixaxe book defines Binding objects to:

encapsulate the execution context at some particular place in the code and retain this context for future use.

You can get a Binding for the current context by calling Kernel#binding.

The Binding stores information about the variables, methods, and self and you can access them by passing the Binding to eval.


  class Product
    def set_title(title)
      @title = title
    end

    def get_binding
      binding
    end
  end

  p = Product.new
  p.set_title("nice and shiny")

  q = Product.new
  q.set_title("old and ugly")

  eval "@title", p.get_binding    # => "nice and shiny"
  eval "@title", q.get_binding    # => "old and ugly"

You can see here that @title gets evaluated differently depending on the binding. The first eval returns "nice and shiny" because that is the value of @title for the first Product p.

Blocks and Procs

Blocks carry information about their Binding.



  a = "inside a"
  a_block = lambda { a }

  def try_to_set_a(block)
    a = "resetting a"
    block.call
  end

  try_to_set_a(a_block)          # => "inside a"


Notice here that a is "inside a" and not "resetting a". This is beacuse a block stores the variables as they were originally defined. The a in try_to_set_a does not interfere with the a in a_block.

An interesting note is that you can redefine variable within a Binding.

  a = "inside a"
  a_block = lambda { a }

  def try_to_set_a(block)
    a = "resetting a"
    block.call
  end

  eval "a = 'something else'"
  try_to_set_a(a_block)          # => "something else"

This is because the Binding in this case is the top-level binding which happens to be the same binding in which a was defined in originally.

Practical Use

Bindings are often used when evaluating ERB. (For those of you who don’t know, ERB is a template system that is included in the Ruby Standard Library.)

ERB#result takes a Binding object as its argument and the variables in the ERB template are evaluated in this context.

Going back to our Product example from earlier, lets see how we can use the Product’s bindings in this fashon:

  require 'erb'

  class Product
    def set_title(title)
      @title = title
    end

    def set_cost(cost)
      @cost = cost
    end

    def get_binding
      binding
    end
  end

  p = Product.new
  p.set_title("nice and shiny")
  p.set_cost("19.95")

  q = Product.new
  q.set_title("old and ugly")
  q.set_cost("230.00")

  template = ERB.new <<-EO_ERB
    == Invoice
    Title: <%= @title %>
    Cost:  <%= @cost  %>
  EO_ERB

  template.result(p.get_binding)   # => "  == Invoice\n  Title: nice and shiny\n  Cost:  19.95\n"
  template.result(q.get_binding)   # => "  == Invoice\n  Title: old and ugly\n  Cost:  230.00\n"

Conclusion

As you can see Binding is a very handy object but this article serves as only an introduction to the subject. Here are a couple articles that deal with binding a little more in-depth.

Jim Weirich’s Variable Bindings in Ruby
Pick Axe page on Binding

Labels: , ,

Testing Private Methods

Friday, March 09, 2007 by Nate Murray.

This probably isn't news to most of you, but it might help someone. Sometimes you want to test private methods. If you want you can just set the method to be public from within a #class_eval. Then call it in your test. For example:

def test_private_method
  product = products(:first) # grab our fixture
  product.class.class_eval do
    public :some_private_method
  end

  assert product.some_private_method
end

Labels: , ,

Directory Trees

Tuesday, March 06, 2007 by Nate Murray.

Below is a code snippet for putting directory tree into a data structure. Basically what I wanted was for each folder to be a hash with the key being the folder name and the value was an array of the files and folders it contains. For example: The folders:

       content/policy
       content/policy/privacy_policy.txt
       content/policy/about_us.txt
       content/policy/mean_policy
       content/policy/mean_policy/nice_people.txt
       content/policy/mean_policy/mean_people.txt
       content/index.txt
       content/content
       content/content/misc
Creates the structure:
      {"content"=>
         [{"content"=>[{"misc"=>[]}]},
           "index.txt",
          {"policy"=>
            ["about_us.txt",
            {"mean_policy"=>["mean_people.txt", "nice_people.txt"]},
             "privacy_policy.txt"]}]}
The recursive code snippet is posted below:
    def content_files_in_dir(dir, results = {}, opts = {})
      return nil unless File.exist?(dir)
      entries = Dir.entries(dir).delete_if { |f| f =~ /^\./ }

      key = File.basename(dir)
      values = []

      entries.each do |entry|
        full_entry = File.join(dir, entry)
        values << ( File.directory?(full_entry) ?
          content_files_in_dir(full_entry, results, opts) :
          entry )
      end
      { key => values }
    end

Labels: , ,

Using Parameters as Default Parameters

by Nate Murray.

I noticed something interesting about arguments in parameters today. You can actually use default parameters in data structures in other default parameters. For instance:

[nathan@nate ~]$ irb
>> def foo(arg1, arg2 = [arg1])
>>   puts arg1.inspect
>>   puts arg2.inspect
>> end
=> nil
>> foo 3
3
[3]
=> nil

Labels: , ,

Dealing with Collections in Rails Views

Wednesday, February 14, 2007 by Nate Murray.

Often, we want to render collections of things in Rails views. In this example the end goal is to output a list of Category names with urls. This is often referred to as "breadcrumbs"

Example 1

For our breadcrumbs the first thing one might think to do is create a helper to perform this function.

For those of you who are new to Rails, helpers are often designed to return a string and this string is added to the output.

Below is our first attempt at a helper for this problem. This code returns a string with our anchor tags separated by an image.

== helpers/sites_helper.rb

  def make_breadcrumbs(breadcrumbs)
    crumbs = []  
    spacer = "<img src='/images/separator.gif' width=5 height=5
        border=0>"
    breadcrumbs.each do |crumb|
      crumbs <<  "<a href='#{url_for_category(crumb)}'>
       #{crumb.name}</a>"
    end
    return crumbs.join(spacer)
  end

We can call this helper easily from our view:

== views/sites/_breadcrumbs.rhtml

 <%= make_breadcrumbs(@breadcrumbs) %>

This works just fine, but there are a couple consequences:

  • its very specific to our problem.
  • All the HTML is in the code instead of in our views.

Example 2

"But wait a minute," you ask, "Doesn't Rails come with built-in collection-rendering methods?" You're right! In fact we can use Rails render method to achieve the same effect.

== views/sites/_breadcrumbs.rhtml

 <%= render :partial => "sites/breadcrumb", 
               :collection => @breadcrumbs,
               :spacer_template => 'sites/breadcrumb_spacer' %>

In our view we call the render method and we pace the options :collection and :spacer_template. This renders the partial sites/breadcrumb and creates the local variable breadcrumb with each element of @breadcrumbs.

The two templates are below:

== views/sites/_breadcrumb.rhtml
<a href='<%= url_for_category(breadcrumb)%>'><%=breadcrumb.name%></a>
== views/sites/_breadcrumb_spacer.rhtml
<img src='/images/separator.gif' width=5 height=5 border=0>

A benefit of this is that all of our HTML is in our views.However, a consequence that we have to create two new partials that contain only one line each.

What we would really want is a way to keep all of our html in our view while not having to create any extra templates.

Example 3

Here is an example of the syntax we want:

== views/sites/_breadcrumbs.rhtml

 <% spacer = capture do %>
   <img src="/images/separator.gif" width=5 height=5 border=0>
 <% end %>
 
 <% with_collection @breadcrumbs, :spacer_template => spacer do |crumb| %> 
   <a href='<%= url_for_category(crumb) %>'><%= crumb.name %></a>
 <% end %>


The Rails helper capture takes the block and puts it in the variable spacer.

Then we put this in helpers/sites_helper.rb

== helpers/sites_helper.rb

  def with_collection(collection, opts={}, &proc)
    collection.each_with_index do |element, i|
      yield element
      if spacer = opts[:spacer_template]
        concat(spacer, proc.binding) unless i == collection.size - 1
      end
    end
  end

This helper takes the collection and yields each element. As each element is yielded the block in the view is added to the output. The trick is that we add the spacer to the output by using the concat method. The concat method outputs the string to the view from the helper. This is how we can output something to the template without using <%= (This is also what the helpers such as form_for use).

Labels: , , ,

Finding a Better State Pattern (in Ruby)

Wednesday, February 07, 2007 by Nate Murray.

Introduction

Gang of Four outlines a pattern for modifying an object depending on its state. This is called the State pattern. I'm not going to go into all the details here, so if you are unfamiliar with the State pattern I'd recommend looking here and here.

This post addresses how to implement the typical State pattern in Ruby and explores its consequences and alternatives.

Problem: An object's behavior needs to be modified depending on what state it is in.
Solution: Create a State object and delegate the functionality to that State object.

Traditional State Pattern

Gang of Four outlines a pattern for modifying an object depending on its state. This is typically done be creating an Abstract State and then subclassing it to create a Concrete State. The originating object, referred to as the Context then delegates the specific method to an instance of the Concrete State along with any information needed.

For example, say we have a Product and we want the inventory levels to vary depending on where we are selling the Product. While the actual inventory we have doesn't change, we may want to tell, say, eBay or Amazon, that the inventory is lower than what we actually have to prevent overselling.

Figure 1. is a traditional implementation of this.

A simple implementation would delegate the method to the state 100% of the time. However, in our system, assume that we only want to use the State if it exists and if it contains the method we are interested in. This allows us to have default behaviors in our Product object. This may not always be the case, but in our example it is.

In Ruby, this looks something like the following:

class Product
  attr_accessor :state

  def inventory
    if state && state.respond_to?(:inventory)
      return state.send(:inventory, self)
    else
      return @inventory
    end
  end

end # end Product

class AmazonProductState < ProductState
  
  # take the inventory from the Context object (the Product) and divide it by 2
  def inventory(context)
    context.inventory / 2
  end

end

Consequences

  • A consequence of this approach is that you have to write the lines if state && state.respond_to?(:inventory) return state.send(:inventory, self) every time. Ideally we wouldn't have to write this over and over for every method we want to delegate.

A slight improvement

What we could do is write a method that writes the delegation code for the method for us.


def define_state_method(name, &block)
  # ... 
end

# Then just call that method fo r
define_state_method :quantity_on_hand do
  return @inventory
end # writes #1 in effect

Consequences

  • Eliminates the repetition of #1
  • However, you still have to plan ahead to make this method be delegated to the State object.

Ideally, what we want to do is have any method overwritten for a particular instance when the state is set. We want to keep the same class, and we don't want to change the methods of other instances of that class.

Just extend it

We can achive the affect we are looking for by simply extending the class on our Product object. See below:

class AmazonProductState < ProductState
  def inventory
    @inventory / 2
  end
  
  def new_method
    "7 llamas"
  end
end

class Product
  ...
  def set_state(klass)
    self.instance_eval do
      extend klass
    end
  end
  ...
end
>> p = Product.find(1) # => #<Product:@id=1...>
   q = Product.find(1) # => #<Product:@id=1...>
   
   q.inventory # => 10

   p.set_state(AmazonProductState) # => nil
   p.inventory # => 5

   p.respond_to(:new_method) # => true
   q.respond_to(:new_method) # => false

Consequences

  • Allows us to override any method without having to plan ahead when designing the Product object
  • Allows us to add new methods that only exist in the state
  • The new state does not change the class of the object
  • The new state only affects particular instances of the object, not the whole class

Labels: , , , ,

Higher Order Procedures (in Ruby)

Wednesday, December 13, 2006 by Nate Murray.

Functions that take other functions as a parameter or return functions as a result are called Higher-Order Procedures. This concept was made clear to me through the MIT video lectures of Structure and Interpretation of Computer Programs (1985 MIT Press) by Hal Abelson and Gerald Jay Sussman. I have created a small presentation that tries to boil down these powerful concepts and converted the Lisp code to Ruby. The copy is taken almost directly from SICP with a few paraphrases and additional examples added. You can view the presentation with notes at Slide-Share here. Or you can download the presentation as:

Labels: , ,

Rookie Ruby Mistake

Thursday, October 12, 2006 by Nate Murray.

I made a rookie mistake today, so I thought I'd share it. Consider the following code:

s = "hello world"
a = ["foo", "bar", s]

other_s = s            # not a copy!
other_s.upcase!

puts a[2]              # => "HELLO WORLD"

Notice that the contents of a were changed. This is because the variable other_s is simply a reference to the same object that is in a. It's such a simple thing to overlook when things are more complicated. It's subtle and that can make it difficult to track down.

The lesson? When you edit an object in place make sure that is what you want!

Labels:

Ruby Debugger

by Nate Murray.

I just started to learn the ruby debugger. Its pretty helpful in those cases where puts just doesn't cut it. I found a good introductory article on this over at IBM: Debugging Ruby programs 101 (registration required). One of the most annoying things was that there seemed to be a catchpoint on every single exception that was raised. I had to keep hitting c just to get to my first actual breakpoint. I found the solution to this problem over at comp.lang.ruby. Basically, there is a default catchpoint on StandardError so you are prompted at all raise exceptions. What you need to do to fix this is just set a catchpoint for your own type of error. So when you start up simply:

  cat MyOtherError

It will remove the default catchpoint and catch only on MyOtherError.

Another helpful Ruby Debugger tip is to have the debugger load a debug.rc file on startup. Matthias Georgi posted this hack on comp.lang.ruby that could be helpful.

A short hack.
Make a copy of debug.rb and put these lines right after the Context
class.

class Context
  alias original_readline readline
  def readline(prompt, hist)
    @rc_file ||= File.readlines("debug.rc")
    if @rc_file.empty?
      original_readline(prompt, hist)
    else
      @rc_file.shift
    end
  end
end

Now create a file debug.rc with your desired breakpoint:
b 100
b 200

Start the debugger:
ruby -r./debug myscript.rb 

Of course, this isn't a totally clean solution in that you are editing a standard file. Also, I don't think this code would work if the debug.rc file did not exist. Nonetheless, its the easiest method I've seen so far.

Labels:

BackupGem

Tuesday, October 10, 2006 by Nate Murray.

I've just released the first version of my BackupGem. You can read the manual here: http://tech.natemurray.com/backup/ BackupGem aims to be the easiest and most flexible backup, archive and rotate tool. It’s a beginning-to-end solution for scheduled backups in a clean ruby package that is simple use and powerful when customized. A configuration as simple as:

  set :backup_path, "/var/local/backups/my_old_logs"
  action :content,  :is_contents_of => "/var/my_logs"

Will compress, encrypt, deliver, and rotate the contents of /var/my_logs. But this is just a taste of the power this gem has.

If you are interested the gem is available via:

  gem install backupgem

Or view the manual at: http://tech.natemurray.com/backup/
RubyForge Project page: http://rubyforge.org/projects/backupgem/

Labels: , ,

Who we are:
The Pasadena Ruby Brigade is a group of programmers who are interested in Ruby. We enjoy sharing our ideas and code with anyone who is interested in this wonderful programming language.

Who can join:
Anyone! Just head over to our mailing list and drop us an email.

What we do:
We recently started a project over at RubyForge. This project is a group of programs written and maintained by our members that we thought could be beneficial to the whole community.

Projects

Downloads

Recent Posts

Archives