22 July, 2011

Chromium Updater

I have been using Martin Endres' Chromium Updater for quite a while, but last month the program stopped working because of URL changes for continuous and snapshot channel. Only a couple scripts were posted since to keep Chromium updated. With the source code unavailable, I decided to start from scratch to learn, but looking for ideas from similar tools.

The Chromium Updater executable can be downloaded here below.
chromiumupdater.zip (32bit)
size: 6650byte
md5sum: 7957845c1f7199c3904cfcfb471da110
sha1sum: a377cf533e5823b2c993afb9822607cd47fa1575

Let me know if there are problems with it, and also if it works.

The Chromium Updater is simple; it does less than the original. It downloads the latest build from the snapshot channel and installs it. It has to be run manually (it probably can be started from the Startup folder) and the update has to be started manually as well. The registry setting created by Martin Endres' Chromium Updater is reused (or created if you have not used it before). I have tested it on Windows7 (64bit).

I plan to make the source accessible, I have not yet decided how and where. I like to (slowly) add more functionality, like a configurable channel address. Comments on both are very welcome.

Update 24. July, 2011:

I fixed two bugs, one causing a crash when accessing the registry, another causing the Chromium download to fail. Also, I removed the requirement of .Net 4.0; now only 3.5 is needed, which comes with Windows7 by default.
chromiumupdater.zip (32bit)
size: 10911byte
md5sum: a5291b3ec5148a339778adcb1623bf0a
sha1sum: d5def4690acb51492474af11042957c5dea510ef

Update 3. August, 2011:

A new version of the Chromium Updater is available, which allows to install Chromium from different (configurable) channels. Currently three channels are available, Snapshot, Webkit-Snapshot and Continuous channel.
chromiumupdater.zip (32bit)
size: 13486byte
md5sum: 82c7b3f28cd7cd761140b631f61304ce
sha1sum: a8e7e1d4b06dd4e6e3eca591de86d3185eea3d2c


16 October, 2010

Simple Perl Plugins

Even with quite some searching and reading about Perl I could not find a small, but complete example for how to create a plugin system for a perl project.

I found Module::Pluggable, but not being a perl expert the documented example was not enough to get a working proof of concept. I was also pointed to Moose's roles and traits. With a minimal example with a minimal number of dependencies as goal, Module::Pluggable was preferred.

My minimal example, based on Email::Send, has three parts:

Main script (./plugin-test.pl):

#!/usr/bin/perl 

use FindBin; # find the name and path of the current file
use lib $FindBin::Bin; # add as lib path, to find modules
# (hack; better put modules in correct path)

# This module provides a simple, clean interface to multiple plugins.
# It can be easily extended by plugins. For example see PluginA, PluginB.
# The idea is taken from the Email::Send modules by Casey West.
use PMT::Test;

my $tester = PMT::Test->new; # create new object
$tester->work(); # do work

my @available = $tester->get_all_plugins(); # get all plugins
print( "LIST={@available}\n");

my $res = $tester->is_plugin_available( 'PluginA'); # check plugin availibility
printf( "PluginA available=%s!\n", $res ? "Yes" : "No");
$res = $tester->is_plugin_available( 'PluginC');
printf( "PluginC available=%s!\n", $res ? "Yes" : "No");

# _plugin_selected is the plugin that should be used; not defined by default
PMT::Test->new( { _plugin_selected => 'PluginA'})->work( "test-data");
PMT::Test->new()->work( "test-data2");


Plugin-managing package (./PMT/Test.pm):
package PMT::Test;
use strict;

use Module::Pluggable search_path => 'PMT::Test';

# create a new object of type $class
sub new {
  my( $class, $args) = @_; # args can contain any field, see BEGIN below

  my %plugins = map {
    my( $short_name) = /^${class}::(.+)/; # remove class name to get short name
    ( $short_name, $_);
  } $class->plugins; # loop through Module::Pluggable->plugins
  $args->{ _plugin_list} = \%plugins; # store plugin list in args

  return bless( $args => $class);
}

# this is run after reading the file, before compiling everything else
BEGIN {
  for my $field( qw( _plugin_selected _plugin_list)) {
    my $code = sub { # create a sub for each field
      return $_[0]->{ $field} unless @_ > 1; # return field for an object of this class
      my $self = shift;
      $self->{ $field} = ( @_ == 1 ? $_[ 0] : [ @_]); # or storing the field if @_ > 1
    };

    no strict 'refs';
    *$field = $code;
  }
}

# returns a list of all plugins
sub get_all_plugins {
  my $self = shift();
  return keys %{ $self->_plugin_list}; # return all keys from the _plugin_list hash
}

# return of the given plugin is in the plugin list
sub is_plugin_available {
  my( $self, $plugin) = @_;
  return grep( $_ eq $plugin, $self->get_all_plugins()); # grep for $plugin in plugin list
}

# make plugin(s) work on data
sub work {
  my( $self, $data) = @_;

  if( $self->_plugin_selected ) { # if a plugin is already selected, use it
    return $self->_try_plugin( $self->_plugin_selected, $data);
  }

  return $self->_try_all_plugins( $data); # try all if no plugin is selected
}

# loop over all plugins and make them work on $data
sub _try_all_plugins {
  my( $self, $data) = @_;

  foreach( $self->get_all_plugins) {
    my $success = $self->_try_plugin( $_, $data);
    #return 1 if $success; # if plugins should only be run until the first success
  }
  #return 0; # no success if no plugin was successful
}

# make $plugin work on $data
sub _try_plugin {
  my( $self, $plugin, $data) = @_;
  my $invocant = $self->_get_plugin_invocant( $plugin); # get the plugin
  return $invocant->work( $data);
}

# get the plugin
sub _get_plugin_invocant {
  my( $self, $plugin) = @_;

  return $plugin if Scalar::Util::blessed( $plugin); # if blessed, return package name

  # is the mailer a plugin given by short name?
  my $package = exists $self->_plugin_list->{$plugin} 
    ? $self->_plugin_list->{$plugin} 
    : $plugin;
  eval "require $package" or return;
  return $package;
}

1;

__END__


Plugin package (./PMT/Test/PluginA.pm):
package PMT::Test::PluginA;

use strict;

sub work {
  my ($class, $message) = @_;
  printf( "PluginA.work( '%s', '%s')\n", $class, $message);
  return 1; # success
}

1;

__END__


It's better than no example, but likely not perfect. So please comment about errors or improvements.