News » WNin #1: improved CLI tool

Written July 12th, 2008.

What's New in nanoc 2.1

Welcome to the first installment of What’s New in nanoc 2.1! This installment introduces the first new important feature of nanoc 2.1: the improved commandline interface, which is not only a lot prettier but offers a few new features as well.

The first of these new features includes built-in commandline help for every command. For example, the compile command has a help page that looks like this:

nanoc compile [options] [path]

compile pages and assets of this site

    Compile all pages and all assets of the current site. If a path is given,
    only the page or asset with the given path will be compiled. Additionally,
    only pages and assets that are outdated will be compiled, unless specified
    otherwise with the -a option.

options:

    -a --all        compile all pages and assets, even those that aren't
                    outdated

As you can see, the compile command has grown up a bit and it’s now possible to tell nanoc only to compile a single page instead of the entire site. Note that nanoc also no longer compiles pages unless they’re considered “outdated”—a real time saver.

Also neat is that command abbreviations are detected automatically. The co command, for example, will be expanded to compile because there’s no other command starting with co. Additionally, if you type something ambiguous, you’ll be notified:

> nanoc c
nanoc: ‘c’ is ambiguous:
  create_template create_site create_page create_layout compile

Error reporting has also been improved. If a compilation error occurs at some point, the stack of what was being compiled will be printed. The following example shows that something went wrong when compiling the “meta” layout, which was rendered from inside the “journal_archive” layout, which in turn was rendered from inside the “journal/2008” page:

Compilation stack:
  - [layout] /meta/
  - [layout] /journal_archive/
  - [page]   /journal/2008/ (rep default)

Of course, the actual error message and the Ruby stack trace will be printed as well, which should make debugging any accidental errors on your site quite a bit easier. (Ignore the “rep” thing for now. We’ll talk about that later.)

When passing the --verbose switch to the compile command, a pretty table containing some profiling information will be printed. Very useful if you want to optimize some of your custom filters. For example, this is the output for my personal web site:

                        | count    min    avg    max     tot
------------------------+-----------------------------------
                    erb |    95  0.00s  0.01s  0.23s   0.74s
image_science_thumbnail |    69  0.22s  0.27s  0.35s  18.51s
              bluecloth |     2  0.06s  0.10s  0.15s   0.21s
      website_thumbnail |    12  0.25s  0.48s  0.97s   5.80s
            compile_css |     2  0.00s  0.00s  0.00s   0.00s
              rubypants |    53  0.01s  0.03s  0.09s   1.39s
              rdiscount |    11  0.00s  0.00s  0.01s   0.02s

This shows that the “compile_css” as well as “rdiscount” filters are extremely fast, while the “image_science_thumbnail” and especially the “website_thumbnail” filters are really slow. (Those thumbnail filters are filters that apply to image assets, not to pages—asset compilation is something that’ll be discussed later).

Last but not least: it’s now possible to write your own commands. Even though rake is sufficient for performing simple tasks, sometimes you need a more advanced tool that allows passing commandline arguments. Now you can write custom commands. Here’s a “Hello World” example:

require 'nanoc/cli'

class HelloWorldCommand < Nanoc::CLI::Command

  def name
    'hello_world'
  end

  def aliases
    %w( hw )
  end

  def short_desc
    'print a simple greeting'
  end

  def long_desc
    'Print the "hello world" greeting on the screen, in either ' +
    'lowercase or uppercase. Can also print a custom text.'
  end

  def usage
    "nanoc hello_world [options] [custom_text]"
  end

  def option_definitions
    [
      # --uppercase
      {
        :long => 'uppercase', :short => 'u', :argument => :forbidden,
        :desc => 'print the text in uppercase instead of lowercase'
      }
    ]
  end

  def run(options, arguments)
    # Get text
    text = (arguments[0] || 'hello world')

    # Print it
    puts (options.has_key?(:uppercase) ? text.upcase : text.downcase)
  end

end

Some example output:

> nanoc hello_world blah
blah
> nanoc hw -u blah
BLAH
> nanoc hello -u
HELLO WORLD
> nanoc hw
hello world

The auto-generated help page:

nanoc hello_world [options] [custom_text]

aliases: hw

print a simple greeting

    Print the "hello world" greeting on the screen, in either lowercase or
    uppercase. Can also print a custom text.

options:

    -u --uppercase  print the text in uppercase instead of lowercase

That’s it for now. Stay tuned for the second installment of What’s New in nanoc 2.1, which will discuss changes to the internals of nanoc and their implications.