public
Description: A mini view framework for console/irb that's easy to use, even while under its influence. Console goodies include a no-wrap table, auto-pager, tree and menu.
Homepage: http://tagaholic.me/hirb/
Clone URL: git://github.com/cldwalker/hirb.git
hirb /
name age message
file CHANGELOG.rdoc Loading commit data...
file LICENSE.txt Tue Mar 10 21:13:12 -0700 2009 more docs, rakefile,license + readme [cldwalker]
file README.rdoc Sun Mar 15 12:59:00 -0700 2009 readme tweak [cldwalker]
file Rakefile Sun Mar 15 13:10:05 -0700 2009 added changelog [cldwalker]
file VERSION.yml
file hirb.gemspec
directory lib/
directory test/
README.rdoc

Description

Hirb currently provides a mini view framework for console applications, designed with irb in mind. Given the output of a console application, it renders a view if there is one configured, based on the output’s class. The framework encourages reusing views by letting you package them in classes and associate them with any number of output classes. Hirb comes with table views (see Hirb::Helpers::Table) which work out of the box with any output class, especially Rails’ model classes.

Install

Install the gem with:

    sudo gem install cldwalker-hirb -s http://gems.github.com

Rails Example

Let’s load and enable the view framework:

  bash> script/console
  Loading local environment (Rails 2.2.2)
  irb>> require 'hirb'
  => true
  irb>> Hirb::View.enable
  => nil

The default configuration provides table views for ActiveRecord::Base descendants. If a class isn’t configured, Hirb reverts to irb’s default echo mode.

  irb>> Hirb::View.output_config
  => {"ActiveRecord::Base"=>{:class=>"Hirb::Views::ActiveRecord_Base", :ancestor=>true}}

  # Tag is a model class and descendant of ActiveRecord::Base
  irb>> Tag.last
  +-----+-------------------------+-------------+---------------+-----------+-----------+-------+
  | id  | created_at              | description | name          | namespace | predicate | value |
  +-----+-------------------------+-------------+---------------+-----------+-----------+-------+
  | 907 | 2009-03-06 21:10:41 UTC |             | gem:tags=yaml | gem       | tags      | yaml  |
  +-----+-------------------------+-------------+---------------+-----------+-----------+-------+
  1 row in set

  irb>> 'plain ol irb'
  => 'plain ol irb'
  irb>> :blah
  => :blah

From above you can see there were no views configured for a String or a Symbol so Hirb defaulted to irb’s echo mode. Also note that Tag was able to inherit its view from the ActiveRecord::Base config because it had an :ancestor option.

Now that you understand that Hirb displays views based on an output object’s class, you may appreciate it also detects configured output objects in an array:

  irb>> Tag.all :limit=>3, :order=>"id DESC"
  +-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
  | id  | created_at              | description | name              | namespace | predicate | value    |
  +-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
  | 907 | 2009-03-06 21:10:41 UTC |             | gem:tags=yaml     | gem       | tags      | yaml     |
  | 906 | 2009-03-06 08:47:04 UTC |             | gem:tags=nomonkey | gem       | tags      | nomonkey |
  | 905 | 2009-03-04 00:30:10 UTC |             | article:tags=ruby | article   | tags      | ruby     |
  +-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
  3 rows in set

At any time you can disable Hirb if you really like irb’s lovely echo mode:

  irb>> Hirb::View.disable
  => nil
  irb>> Tag.all :limit=>3, :order=>"id DESC"
  => [#<Tag id: 907, name: "gem:tags=yaml", description: nil, created_at: "2009-03-06 21:10:41",
  namespace: "gem", predicate: "tags", value: "yaml">, #<Tag id: 906, name: "gem:tags=nomonkey",
  description: nil, created_at: "2009-03-06 08:47:04", namespace: "gem", predicate: "tags", value:
  "nomonkey">, #<Tag id: 905, name: "article:tags=ruby", description: nil, created_at: "2009-03-04
  00:30:10", namespace: "article", predicate: "tags", value: "ruby">]

Views: Anytime, Anywhere

While preconfigured tables are great for database records, sometimes you just want to create tables/views for any output object:

  #These examples don't need to have Hirb::View enabled.
  irb>>Hirb::View.disable
  =>nil

  # Imports table() and view()
  irb>>extend Hirb::Console
  =>main

  # Create a table of Dates comparing them with different formats.
  irb>> table [Date.today, Date.today.next_month], :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
  +------------+--------+-----------+-------+--------------------------+
  | to_s       | ld     | ajd       | amjd  | asctime                  |
  +------------+--------+-----------+-------+--------------------------+
  | 2009-03-11 | 155742 | 4909803/2 | 54901 | Wed Mar 11 00:00:00 2009 |
  | 2009-04-11 | 155773 | 4909865/2 | 54932 | Sat Apr 11 00:00:00 2009 |
  +------------+--------+-----------+-------+--------------------------+
  2 rows in set

  # Same table as the previous method. However view() will be able to call any view created.
  irb>> view [Date.today, Date.today.next_month], :class=>Hirb::Helpers::ObjectTable,
    :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]

If these console methods weren’t convenient enough, try:

  # Imports view() to all objects.
  irb>> require 'hirb/import_object'
  =>true
  # Yields same table as above examples.
  irb>> [Date.today, Date.today.next_month].view :class=>Hirb::Helpers::ObjectTable,
    :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]

Although views by default are printed to STDOUT, they can be easily modified to write anywhere:

  # Setup views to write to file 'console.log'.
  irb>> Hirb::View.render_method = lambda {|output| File.open("console.log", 'w') {|f| f.write(output) } }

  # Writes to file with same table output as above example.
  irb>> view [Date.today, Date.today.next_month], :class=>Hirb::Helpers::ObjectTable,
    :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]

  # Doesn't write to file because Symbol isn't configured to use Hirb::View and thus defaults to irb's echo mode.
  irb>> :blah
  =>:blah

  # Go back to printing Hirb views to STDOUT.
  irb>> Hirb::View.reset_render_method

Create and Configure Views

Let’s create a simple view and configure it in different ways to be Hash’s default view:

Setup

  irb>> require 'hirb'
  =>true
  irb>> Hirb::View.enable
  =>nil
  irb>> require 'yaml'
  =>true

Configure As View Method

A view method is the smallest reuseable view.

  # Create yaml view method
  irb>> def yaml(output); output.to_yaml; end
  =>nil

  # Configure view and reload it
  irb>>Hirb::View.output_config = {"Hash"=>{:method=>:yaml}}
  =>{"Hash"=>{:method=>:yaml}}
  irb>>Hash::View.reload_config
  =>true

  # Hashes now appear as yaml
  irb>>{:a=>1, :b=>{:c=>3}}
  ---
  :a : 1
  :b :
    :c : 3
  => true

Configure As View Class

A view class is suited for more complex views. View classes can be under any namespace and are expected to provide a render method. However, if a class is under the Hirb::Views namespace, it will be automatically loaded with no configuration. Something to think about when sharing views with others.

  # Create yaml view class
  irb>> class Hirb::Views::Hash; def self.render(output, options={}); output.to_yaml; end ;end
  =>nil
  # Just reload since no configuration is necessary
  irb>>Hirb::View.reload_config

  # Hashes now appear as yaml ...

Although the Hirb::Views namespace is great for quick classes that just plug and play, you often want view classes that can be reused with multiple outputs. For this case, it’s recommended to use the Hirb::Helpers namespace.

  # Create yaml view class
  irb>> class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
  =>nil

  # Configure view and reload it
  irb>>Hirb::View.output_config = {"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
  =>{"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
  irb>>Hirb::View.reload_config

  # Hashes now appear as yaml ...

Configure At Startup

Once you know what views are associated with what output classes, you can configure them at startup by passing Hirb::View.enable a block:

  # In .irbrc
  require 'hirb'
  # View class needs to come before enable()
  class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
  Hirb::View.enable {|conf| conf.output = {"Hash"=>{:class=>"Hirb::Helpers::Yaml"}} }

Or by creating a config file at config/hirb.yml or ~/.hirb.yml:

  # The config file for the yaml example would look like:
  # ---
  # :view :
  #  :output :
  #    Hash :
  #      :class : Hirb::Helpers::Yaml

  # In .irbrc
  require 'hirb'
  # View class needs to come before enable()
  class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
  Hirb::View.enable

Contributing Views

If you have views of your own you’d like to share, fork Hirb and put your views under the Hirb::Helpers namespace and the view files under lib/hirb/helpers/.

Limitations

Although Hirb preserves Wirble colorizing irb’s default echo mode, it doesn’t colorize its own views. This is mainly because colorizing caused table classes to render incorrectly. If you can get tables and colors to work nicely, please fork. To colorize your Hirb output:

  Hirb::View.render_method = lambda {|output| puts Wirble::Colorize.colorize(output) }

Motivation

Table code from gist.github.com/72234 and my console app.

Links

Todo

  • Create tree views.
  • Possibly add non-view irb goodies ie command manager.
  • Configurable max height, which if exceeded activates a pager.
  • Provides helper methods to all view classes.
  • Consider adding a template system as needed.