08/27 2014

Working with pp: the Ruby Pretty Printer

Last week, I worked on making the Riak CRDTs print out nicer in the Riak Ruby client. Since my main interaction with riak-client is through the pry REPL and RSpec, I decided to use the pp stdlib library to make the output nicer.

ugly irb output

Out of the box, a Riak CRDT set looked like:

#<Riak::Crdt::Set:0x007fbec39d87b0 @bucket=#<Riak::Bucket {bucketname}, @key="cats", @bucket_type="sets", @options={}, @dirty=true>

This was terrible for several reasons: the actual value of the set wasn’t listed, the object_id is a ridiculous thing, and the bucket type/bucket/key relationship is hard to read. The end goal was something that made it easy to identify which object was which, what it contained, and elide unimportant implementation details.

Ruby’s pp library has some sensible defaults: print out the class name, object_id, and all instance variables. It’s relatively good for objects built out of primitives, but tends to break down on deep data structures. The CRDTs for Riak tend to be deeply-nested, especially the Map type, which can contain Counters, Flags, Maps (which can continue recursing down), Registers, and Sets.

PP Callbacks

The way PP works is a bit convoluted.

  1. You call pp some_object
  2. Kernel.pp calls PP.pp some_object
  3. PP.pp instantiates a PP instance, and calls PP#pp some_object
  4. PP#pp calls some_object.pretty_print self or some_object.pretty_print_cycle self

Working with PP on your own objects isn’t convoluted: create a pretty_print method that takes a PP instance as its only argument, and calls methods on the instance to output what your users need.

In the case of a recursion, you don’t simply want to repeat the same full representation every time, just enough to know that there’s some recursion.

PP Methods

I ended up using very few methods on PP:

  • object_group wraps its contents with angle brackets and general object information
  • breakable inserts a space that can be used as a line break
  • comma_breakable inserts a comma followed by a breakable space
  • text inserts text
  • pp recursively pretty-prints the given value

Examples

On Riak::Crdt::Base, I wanted to provide the basics that Counter, Map, and Set can inherit from. This method prints out the given class, its bucket type, bucket, key, and then yields to the child class:

# on Riak::Crdt::Base
def pretty_print(pp)
  pp.object_group self do
    pp.breakable
    pp.text "bucket_type=#{@bucket_type}"
    pp.comma_breakable
    pp.text "bucket=#{@bucket.name}"
    pp.comma_breakable
    pp.text "key=#{@key}"

    yield
  end
end

On Riak::Crdt::Map, which inherits from Base above, I wrap map-specific fields in the above method. Since it has five sub-collections, I loop over those to pretty-print them individually.

# on Riak::Crdt::Map
def pretty_print(pp)
  super pp do
    %w{counters flags maps registers sets}.each do |h|
      pp.comma_breakable
      pp.text "#{h}="
      pp.pp send h
    end
  end
end

Riak::Crdt::InnerMap doesn’t have a bucket type, bucket, or key. It’s a simple version of what Map does:

# on Riak::Crdt::InnerMap
def pretty_print(pp)
  pp.object_group self do
    %w{counters flags maps registers sets}.each do |h|
      pp.comma_breakable
      pp.text "#{h}="
      pp.pp send h
    end
  end
end

Conclusions

a nicer, colorized pretty-printed map

Pretty-printing is really nice for debugging and playing with Ruby in a REPL. On top of adding pretty-print support to your code, maybe also encourage users to use Pry, which does a great job of colorizing output.

07/09 2014
– View on Path.

– View on Path.

05/04 2014
– View on Path.

– View on Path.

01/24 2014
Friday afternoon office. at Grove Spot – View on Path.

Friday afternoon office. at Grove Spot – View on Path.

01/20 2014
panthercoffee:

This is an incredibly happy moment for us at Panther Coffee as we celebrate not one but three prizes and distinct recognition of our coffee, our work and the great work of our friends, partners and co-workers all along the long and complex coffee chain.

This week Panther received not one but two Good Food Awards in San Francisco: One for Panther Coffee Ethiopia Chelba and another for Panther Coffee Kailash

At the same time in Durham,NC representing Panther Coffee Camila Ramos wins the first place at the Big Eastern SE Barista Competition!
You can watch her winning presentation online athttp://new.livestream.com/SpecialtyCoffeeAssociationOfAmerica/BigEasternEvent/videos/39935696

A very special thank you and huge shout out to Maximo Ramos - producer of Kailash in Nicaragua and his whole team both at the farm and at Virmax.
Watch Dom Maximo telling us more about Kailash here:http://www.panthercoffee.com/post/73484366343/a-short-interview-with-don-maximo-ramos-producer

And many thanks to the whole Panther team and customers for your support and all the intense cheering and love this week. We ❤️ you

panthercoffee:

This is an incredibly happy moment for us at Panther Coffee as we celebrate not one but three prizes and distinct recognition of our coffee, our work and the great work of our friends, partners and co-workers all along the long and complex coffee chain.

This week Panther received not one but two Good Food Awards in San Francisco: One for Panther Coffee Ethiopia Chelba and another for Panther Coffee Kailash

At the same time in Durham,NC representing Panther Coffee Camila Ramos wins the first place at the Big Eastern SE Barista Competition!
You can watch her winning presentation online at
http://new.livestream.com/SpecialtyCoffeeAssociationOfAmerica/BigEasternEvent/videos/39935696

A very special thank you and huge shout out to Maximo Ramos - producer of Kailash in Nicaragua and his whole team both at the farm and at Virmax.
Watch Dom Maximo telling us more about Kailash here:
http://www.panthercoffee.com/post/73484366343/a-short-interview-with-don-maximo-ramos-producer

And many thanks to the whole Panther team and customers for your support and all the intense cheering and love this week. We ❤️ you

1 of 64