Monday, June 18, 2012

On-the-fly Generator of Preferences Pages for Opera Extensions

If you've ever tried to write an Opera extension, then you probably have stumbled upon a process of handling preferences for your extensions.

When a user clinks 'Preferences' in an extension menu button, Opera reads options.html file from the installed extension. What goes to that options.html is up to the developer. Nothing prevents him to display a lolcat video instead of html forms.

The process of writing options.html if everything except creative--it's the same boring crap over & over again for every new extension. I don't get why you even have to do this--Opera could have an API to help automatically generate preferences pages like it have it internally for the browser (opera:config). But there isn't API for this & nobody pushes for it.

So image you're writing in a declarative way what preferences your extension needs & the browser is drawing GUI elements according to your specification. Not code, just a declaration.

If you agree to this approach & don't want to waste your time on a dumb & repetitive staff, see weakspec on-the fly generator. You'll probably like it.

Friday, April 13, 2012

How To Disable Rack Logging in Sinatra

To completely & finally turn the annoying Rack logging off, simple 'set :logging, nil' doesn't help. Instead, insert this monkey patch at the beginning of your Sinatra application:

# Disable useless rack logger completely! Yay, yay!
module Rack
  class CommonLogger
    def call(env)
      # do nothing
      @app.call(env)
    end
  end
end

Custom RDoc's Darkfish Templates

RDoc 3.12 allows us to specify a template for a formatter. Formatter can be 'ri' or such that emits html. The later is called 'darkfish' in RDoc.

The problem with darkfish is that albeit it contains a quite nice navigation, it hurts my eyes:

https://lh5.googleusercontent.com/-g62JInQnNmc/T4dJdslbgQI/AAAAAAAAAXE/jZY55_VNhoo/s800/rdoc-template.png

Dark grey on light grey! Very artistic choice, of course. I believe it's very possible to invent even worse combination, like red on green, but I still don't get how anybody can like the absence of a contrast.

Anyway, here is a solution: another template for darkfish. (Not another formatter.)

RDoc allows that if you install another template as a gem, because it looks for templates only in rdoc/generator/template directory in Ruby's $LOAD_PATH.

What if you want to generate alternate looking html from a particular Rakefile without messing up with system gems?

  1. Copy the original template to some editable place, for example:

    % cp /usr/[...]/1.9/gems/rdoc-3.12/lib/rdoc/generator/template/darkfish \
    /home/alex/Desktop/lightfish
    

    'lightfish' is out new template in this example.

  2. Edit lightfish/rdoc.css to remove ugly colors, fonts, etc.

  3. Add a small monkey patch to your project's Rakefile:

    class RDoc::Options
      def template_dir_for template
        '/home/alex/Desktop/' + template
      end
    end
    
    RDoc::Task.new('html') do |i|
      i.template = 'lightfish'
      i.main = 'README.rdoc'
      i.rdoc_files = FileList['doc/*', 'lib/**/*.rb', '*.rb']
    end
    

    template_dir_for() function is a key to succsess.

  4. Run rake html. RDoc must not complain about 'could not find template lightfish'.

But there is even simpler method with $LOAD_PATH. Make rdoc/generator/template directory somewhere, for example in the project's root directory. Move in it a modified template from steps 1-2 above and just run (assuming rake's target for generating documentation is still called 'html'):

% rake -I . html

Friday, January 27, 2012

Rubygems rdoc spec exclude & rdoc task exclude

One more or less popular error in gemspec:

spec = Gem::Specification.new {|i|
  [...]

  i.rdoc_options << '-m' << 'doc/README.rdoc' << '-x' << 'lib/**/templates/**/*'
  i.extra_rdoc_files = FileList['doc/*']

  [...]
}

In this example a pattern after -x option is invalid. rdoc internally constructs an Regexp object from argument to -x option:

  • If you supply a string 'foo' it will end up as /foo/ argument to a Regexp.new.
  • If you have several -x options like -x foo -x bar, the argument will be /foo|bar/.

(At first rdoc constructs an array from all -x options and then converts it into 1 regexp.)

Now, 'lib/**/templates/**/*' is obviously a bogus regexp and rdoc will loudly complain about it during gem installation. [1] How did it appear in the spec in the first place?

A developer just copied a string from RDoc task which might look like:

RDoc::Task.new('html') do |i|
      i.main = "doc/README.rdoc"
      i.rdoc_files = FileList['doc/*', 'lib/**/*.rb']
      i.rdoc_files.exclude 'lib/**/templates/**/*'
end

This rake task works as intended: 'lib/**/templates/**/*' parameter is a valid one because i.rdoc_files is a Rake::FileList object and exclude method of that object expects such kind of patterns and doesn't understand regexps.

So, don't mix up those patterns it the spec and in the RDoc task itself.

[1]The right one would be something like 'lib/.+/templates/'.