leah blogs

September 2004

26sep2004 · Practical Tangerine

Today, we’ll use Tangerine (download at the end of this post) to convert the ports information file of RPA into a Debian-dctrl-like format. This has some advantages, for example, we will be able to use grep-dctrl and other tools that expect the Debian-format.

The ports.info is a simply YAML file with entries like these:

  metadata: 
    name: progressbar
    rpaversion: "0.0"
    version: 0.8.0-1
    classification: 
      - Top.Library.Development
    description: >
      A text progress bar library.
      Ruby/ProgressBar is a text progress bar library for Ruby. It can indicate
      progress with percentage, a progress bar, and estimated remaining time.
  url: http://rpa-base.rubyforge.org/ports/progressbar_0.8.0-1.rps

So, let’s write a small script to load a YAML file and apply a Tangerine template on it:

require 'yaml'
require 'tangerine'

# Convenient hashes
class Hash
  # Defined methods can be accessed by prefixing with _, e.g. _to_s.
  def method_missing(name, *args)
    name = name.to_s
    name = name[1..-1]  if name =~ /^_/
    self[name]
  end
end

object = YAML.load File.read(ARGV[0])
print Tangerine::RFC822.new(STDIN.read).expand(object)

We also added an extension to Hash to write hash.key instead of hash[key]. This makes using Tangerine easier (The better solution would have been to make YAML generate a OpenStruct, but I just couldn’t get it doing that…).

For testing, the first template: Simply show all packages:

,,(self){,,(metadata.name)
}

Save that into a file, and run it like this:

$ ruby yaml2whatever.rb ports.info < packages.tng

You should now see a list of packages.

This template is interpreted as follows: For each self (i.e. the list of entries), output metadata.name and a newline.

Now, to our debian-like output:

,,(self){,,([metadata]){Package: ,,name
Section: ,,classification
Version: ,,version
,,requires{Depends: ,,(self)}},,#
Url: ,,(url)
Description: ,,(metadata.description.gsub(/^$/, '.'))
}

This template has a small twist. Usually ,,(array){block} would expand the block for each element. But since we only want to save writing metadata. all the time, we need to make an array out of it, therefore ,,([metadata]). The ,,# in the Depends-line stops Tangerine from outputting a superfluous newline (Think % in TeX).

$ ruby yaml2whatever.rb ports.info < debian.tng

Voila, a nice package list. Now, let’s query it, for example all packages related to XML, but show only the package name:

$ ruby yaml2whatever.rb ports.info < debian.tng | grep-dctrl -s Package XML -
Package: copland
Package: gettext
Package: libxml
Package: rake
Package: test-report

Of course, this was an relatively easy job (RPA already has an query mechanism too :-)), but what if we’d like to have HTML or XML output? We’d simply need to adjust the templates without changing any code.

The whole job could have been done using plain Ruby of course, but such programs get confusing quickly due to mixing of code, strings and their escaping.

Download: tangerine-0.3.1.tar.gz
This is a bugfix release without any new features.

Ich trage einen Sturzhelm, weil ich sturzbesoffen bin.

NP: Bob Dylan — License To Kill (Live in Austria)

Copyright © 2004–2018